Spring

봄 반응형 ClientRequest에서 문자열로 본문을 가져오는 것이 좋습니까?

기록만이살길 2022. 11. 11. 00:00
반응형

Spring 반응형 ClientRequest에서 문자열로 본문을 가져오는 것이 좋습니까? 물어보다

1. 질문(문제점):

테스트 방법에서 의 인스턴스 org.springframework.web.reactive.function.client.ClientRequest가 수신됩니다.

HttpMethod, URI 및 본문을 확인하고 싶습니다.

몸을 제외한 모든 것을 얻는 방법은 매우 분명합니다.

ClientRequest request = makeInstance(...);

assertEquals(HttpMethod.POST, request.method());
assertEquals("somewhere/else", request.url().toString());

// ? unclear how to extract body using the BodyInserter

BodyInserter<?, ? super ClientHttpRequest> inserter = request.body();

inserter.insert(%outputMessage%, %context%);

Spring 소스에서 BodyInserters가 테스트되는 방법 을 찾았습니다 . (두 번째 매개변수) 만드는 방법은 다소 명확 BodyInserter.Context하지만 첫 번째 매개변수를 구성하는 방법을 이해할 수 없으므로 요청 본문을 통해 추출할 수 있습니다.

ClientRequest인스턴스 에서 요청 본문을 가져오는 일반적인(또는 최소한 사용 가능한) 방법을 보여주세요 .

2. 해결방안:

이를 수행하는 비교적 간단한 방법을 찾았습니다. 즉, BodyInserters.fromValue()자신의 BodyInserter.

public static class CustomerInserter<T> implements BodyInserter<T, ReactiveHttpOutputMessage> {

    private T body;

    private CustomerInserter(T body) {
        this.body = body;
    }

    public static <T> CustomerInserter<T> fromValue(T body) {
        return new CustomerInserter<T>(body);
    }

    public T getBody() {
        return this.body;
    }

    @Override
    public Mono<Void> insert(ReactiveHttpOutputMessage outputMessage, Context context) {
        Mono<T> publisher = Mono.just(this.body);
        MediaType mediaType = outputMessage.getHeaders().getContentType();
        ResolvableType bodyType = ResolvableType.forInstance(this.body);
        return context.messageWriters().stream()
                .filter(messageWriter -> messageWriter.canWrite(bodyType, mediaType))
                .findFirst()
                .map(item -> (HttpMessageWriter<T>) item)
                .map(writer -> this.write(publisher, bodyType, mediaType, outputMessage, context, writer))
                .orElseGet(() -> Mono.error(unsupportedError(bodyType, context, mediaType)));
    }

    private Mono<Void> write(Publisher<? extends T> input, ResolvableType type,
                                        @Nullable MediaType mediaType, ReactiveHttpOutputMessage message,
                                        BodyInserter.Context context, HttpMessageWriter<T> writer) {

        return context.serverRequest()
                .map(request -> {
                    ServerHttpResponse response = (ServerHttpResponse) message;
                    return writer.write(input, type, type, mediaType, request, response, context.hints());
                })
                .orElseGet(() -> writer.write(input, type, mediaType, message, context.hints()));
    }

    private UnsupportedMediaTypeException unsupportedError(ResolvableType bodyType,
                                                   BodyInserter.Context context, @Nullable MediaType mediaType) {

        List<MediaType> supportedMediaTypes = context.messageWriters().stream()
                .flatMap(reader -> reader.getWritableMediaTypes(bodyType).stream())
                .collect(Collectors.toList());

        return new UnsupportedMediaTypeException(mediaType, supportedMediaTypes, bodyType);
    }
}

간단한 단위 테스트

Response response = webClient.post()
            .uri("/xxx")
            .body(CustomerInserter.fromValue(body)) //
            .retrieve()
            .bodyToMono(Response.class)
            .block();

WebClient webClient = WebClient.builder()
            .baseUrl("http://127.0.0.1:8080")
            .filter((request, next) -> {
                CustomerInserter<?> inserter = (CustomerInserter<?>) request.body();
                // Some things can be done here
                Object body = inserter.getBody();
                return next.exchange(request);
            }).build();
61156827
반응형