Webclient 响应处理程序(成功和错误)不会为空响应主体执行
Webclient response handler (both success & error) does not execute for empty response body
有一个用 OkHttp 实现的异步 REST API 客户端,工作得很好。
出于好奇尝试将其转换为 WebClient,观察到奇怪的行为。
WebClient配置就是这样:
webClient = WebClient.builder()
.defaultHeaders(headers -> headers.add(HttpHeaders.CONTENT_TYPE,
org.springframework.http.MediaType.APPLICATION_JSON_VALUE))
.clientConnector(new ReactorClientHttpConnector(builder -> builder
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout)))
.build();
请求代码:
void getTokenWithWebClient(Consumer<Try<String>> callback) {
webClient.post()
.uri(url)
.syncBody(new MyRequest())
.retrieve()
.onStatus(status -> status.value() != HttpStatus.OK.value(),
rs -> rs.bodyToMono(String.class).map(body -> new IOException(String.format(
"Response HTTP code is different from 200: %s, body: '%s'", rs.statusCode(), body))))
.bodyToMono(MyResponse.class)
.subscribe(rs -> callback.accept(Try.of(() -> validateResponse(Option.of(rs)))),
ex -> callback.accept(Try.failure(ex)));
}
在单元测试中,作为参数传递给此方法的回调完成了我等待的 Future。
因此,当我 运行 在 IDEA 中进行测试时,请求导致响应为空主体(内容长度:0),subscribe() 中的 lambda 永远不会执行- 使用 println 调试验证。
但是当我调试相同的测试时,即使没有设置任何断点,它也会按预期完成并根据结果调用 lambda。
我确实在日志中看到了这个:
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClientOperations - [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522] Received last HTTP packet
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522] USER_EVENT: [Handler Terminated]
[reactor-http-nio-4] DEBUG reactor.ipc.netty.channel.ChannelOperationsHandler - [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522] Disposing context reactor.ipc.netty.channel.PooledClientContextHandler@3547abe3
[reactor-http-nio-4] DEBUG reactor.ipc.netty.channel.PooledClientContextHandler - Releasing channel: [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522]
[reactor-http-nio-4] DEBUG reactor.ipc.netty.resources.DefaultPoolResources - Released [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522], now 0 active connections
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522] READ COMPLETE
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522] READ COMPLETE
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 ! R:localhost/127.0.0.1:58522] CLOSE
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 ! R:localhost/127.0.0.1:58522] INACTIVE
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 ! R:localhost/127.0.0.1:58522] UNREGISTERED
但是出现我的错误的 Mono 卡在了某个地方。
运行 这个在 Windows 7,Oracle JDK8 x64,IDEA 2018 上。
Option/Try 是 vavr 类 (io.vavr:vavr),与这种情况无关。
对于单元测试,我使用 Ratpack 模拟了有问题的 REST API。
尝试使用 exchange() 而不是 retrieve() 并检查 subscribe() lambda 中的状态代码,而不使用 onStatus() - 结果相同。
有什么想法吗?
长话短说,rs.bodyToMono(String.class).defaultIfEmpty("")
挽救了局面
有一个用 OkHttp 实现的异步 REST API 客户端,工作得很好。 出于好奇尝试将其转换为 WebClient,观察到奇怪的行为。
WebClient配置就是这样:
webClient = WebClient.builder()
.defaultHeaders(headers -> headers.add(HttpHeaders.CONTENT_TYPE,
org.springframework.http.MediaType.APPLICATION_JSON_VALUE))
.clientConnector(new ReactorClientHttpConnector(builder -> builder
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout)))
.build();
请求代码:
void getTokenWithWebClient(Consumer<Try<String>> callback) {
webClient.post()
.uri(url)
.syncBody(new MyRequest())
.retrieve()
.onStatus(status -> status.value() != HttpStatus.OK.value(),
rs -> rs.bodyToMono(String.class).map(body -> new IOException(String.format(
"Response HTTP code is different from 200: %s, body: '%s'", rs.statusCode(), body))))
.bodyToMono(MyResponse.class)
.subscribe(rs -> callback.accept(Try.of(() -> validateResponse(Option.of(rs)))),
ex -> callback.accept(Try.failure(ex)));
}
在单元测试中,作为参数传递给此方法的回调完成了我等待的 Future。 因此,当我 运行 在 IDEA 中进行测试时,请求导致响应为空主体(内容长度:0),subscribe() 中的 lambda 永远不会执行- 使用 println 调试验证。
但是当我调试相同的测试时,即使没有设置任何断点,它也会按预期完成并根据结果调用 lambda。
我确实在日志中看到了这个:
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClientOperations - [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522] Received last HTTP packet
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522] USER_EVENT: [Handler Terminated]
[reactor-http-nio-4] DEBUG reactor.ipc.netty.channel.ChannelOperationsHandler - [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522] Disposing context reactor.ipc.netty.channel.PooledClientContextHandler@3547abe3
[reactor-http-nio-4] DEBUG reactor.ipc.netty.channel.PooledClientContextHandler - Releasing channel: [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522]
[reactor-http-nio-4] DEBUG reactor.ipc.netty.resources.DefaultPoolResources - Released [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522], now 0 active connections
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522] READ COMPLETE
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 - R:localhost/127.0.0.1:58522] READ COMPLETE
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 ! R:localhost/127.0.0.1:58522] CLOSE
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 ! R:localhost/127.0.0.1:58522] INACTIVE
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0xeffaded6, L:/127.0.0.1:49265 ! R:localhost/127.0.0.1:58522] UNREGISTERED
但是出现我的错误的 Mono 卡在了某个地方。
运行 这个在 Windows 7,Oracle JDK8 x64,IDEA 2018 上。 Option/Try 是 vavr 类 (io.vavr:vavr),与这种情况无关。 对于单元测试,我使用 Ratpack 模拟了有问题的 REST API。
尝试使用 exchange() 而不是 retrieve() 并检查 subscribe() lambda 中的状态代码,而不使用 onStatus() - 结果相同。
有什么想法吗?
长话短说,rs.bodyToMono(String.class).defaultIfEmpty("")
挽救了局面