WebClient使用exchangeToMono获取ClientResponse时响应体为null问题
WebClient exchangeToMono响应体为null问题解决
我在单元测试中编写代码理解WebClient API时遇到问题:使用exchangeToMono获取的ClientResponse能正确返回200状态码,但响应体始终为null;而使用已废弃的exchange()方法却能正常获取响应内容"Some string response"。
测试代码如下:
@BeforeEach public void setUpTest() throws JsonProcessingException { baseUrl = String.format("http://localhost:%s", mockBackEnd.getPort()); String response = "Some string response"; ObjectMapper objectMapper = new ObjectMapper(); mockBackEnd.enqueue(new MockResponse() .setBody(objectMapper.writeValueAsString(response)) .addHeader(HttpHeaders.CONTENT_TYPE, ContentType.TEXT_PLAIN)); } @Test public void test_clientResponse_return_type() { WebClient webClient = WebClient.builder() .baseUrl(baseUrl) .build(); Mono<ClientResponse> clientResponseMono = webClient.post() .uri(baseUrl) .accept(MediaType.TEXT_PLAIN) .bodyValue("") .exchangeToMono(Mono::just); ClientResponse clientResponse = clientResponseMono.block(); log.info("Response StatusCode is :-" + clientResponse.statusCode()); log.info("Response Body is :-" + clientResponse.bodyToMono(String.class).block()); }
问题原因
exchangeToMono的设计初衷是让开发者在操作符内部完成响应体的消费与处理,当你直接用Mono::just返回ClientResponse时,WebClient会认为响应体未被处理,从而提前关闭响应流,导致后续调用bodyToMono无法读取到内容。
而废弃的exchange()方法将ClientResponse直接暴露到外部,允许在外部消费响应体,但这种方式存在资源泄漏风险(如未消费响应体导致连接池资源无法释放),因此Spring官方已不推荐使用。
解决方案
方案1:在exchangeToMono内部处理响应体(推荐)
直接在exchangeToMono中完成状态码日志打印与响应体读取,这是Spring官方推荐的用法:
@Test public void test_clientResponse_return_type() { WebClient webClient = WebClient.builder() .baseUrl(baseUrl) .build(); Mono<String> responseBodyMono = webClient.post() .uri(baseUrl) .accept(MediaType.TEXT_PLAIN) .bodyValue("") .exchangeToMono(response -> { log.info("Response StatusCode is :-" + response.statusCode()); return response.bodyToMono(String.class); }); String responseBody = responseBodyMono.block(); log.info("Response Body is :-" + responseBody); }
方案2:缓存响应体后返回ClientResponse
如果确实需要获取完整的ClientResponse对象,可以在exchangeToMono内部先缓存响应体,再通过mutate()方法构建新的ClientResponse:
@Test public void test_clientResponse_return_type() { WebClient webClient = WebClient.builder() .baseUrl(baseUrl) .build(); Mono<ClientResponse> clientResponseMono = webClient.post() .uri(baseUrl) .accept(MediaType.TEXT_PLAIN) .bodyValue("") .exchangeToMono(response -> response.bodyToMono(String.class) .map(body -> response.mutate().body(Mono.just(body)).build()) ); ClientResponse clientResponse = clientResponseMono.block(); log.info("Response StatusCode is :-" + clientResponse.statusCode()); log.info("Response Body is :-" + clientResponse.bodyToMono(String.class).block()); }
内容的提问来源于stack exchange,提问作者Mark Gargan
相关产品推荐
相关产品推荐

