Have an async REST API client implemented with OkHttp, works just fine. Trying to convert it to WebClient out of curiosity, observing weird behaviour.
WebClient configuration is just this:
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();
request code:
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)));
}
In the unit test, callback that is passed as an argument to this method, completes a Future, on which I wait. So, when I run the test in IDEA, and the request results in a response with empty body (content-length: 0), the lambdas in subscribe() never execute - verified using println debugging.
But when I debug the same test, even without any breakpoints set, it completes as expected and the lambdas are invoked depending on the result.
I do see this in the log:
[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
but then the Mono with my error gets stuck somewhere.
Running this on Windows 7, Oracle JDK8 x64, IDEA 2018. Option/Try are vavr classes (io.vavr:vavr), not relevant for this case. For unit tests, I mock the REST API in question using Ratpack.
Tried using exchange() instead of retrieve() and checking the status code in the subscribe() lambda, without onStatus() - with the same result.
Any ideas?
While Initialising WebClient As mentioned in the code block, whenever a 5XX/4XX Error occurs, we can throw a user defined exception, and then execute error handling logic based on those user defined exceptions. Once this error Handler is defined, we can add it in the WebClient Initialisation.
Because WebClient is immutable it is thread-safe. WebClient is meant to be used in a reactive environment, where nothing is tied to a particular thread (this doesn't mean you cannot use in a traditional Servlet application).
In this tutorial, we're going to examine WebClient, which is a reactive web client introduced in Spring 5.
long story short, rs.bodyToMono(String.class).defaultIfEmpty("")
saved the day
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With