Defensive checks in WebClient and Reactor connector
Since there is no reason for an exchange to ever complete without a ClientResponse I've added a switchIfEmpty check at the WebClient level. Also, temporarily a second check closer to the problem in the ReactorClientHttpConnector suggesting a workaround and providing a reference to the Reactor Netty issue #138. Issue: SPR-15784
This commit is contained in:
@@ -63,6 +63,10 @@ import org.springframework.web.util.UriBuilderFactory;
|
||||
*/
|
||||
class DefaultWebClient implements WebClient {
|
||||
|
||||
private static final Mono<ClientResponse> NO_HTTP_CLIENT_RESPONSE_ERROR = Mono.error(
|
||||
new IllegalStateException("The underlying HTTP client completed without emitting a response."));
|
||||
|
||||
|
||||
private final ExchangeFunction exchangeFunction;
|
||||
|
||||
private final UriBuilderFactory uriBuilderFactory;
|
||||
@@ -309,7 +313,7 @@ class DefaultWebClient implements WebClient {
|
||||
ClientRequest request = (this.inserter != null ?
|
||||
initRequestBuilder().body(this.inserter).build() :
|
||||
initRequestBuilder().build());
|
||||
return exchangeFunction.exchange(request);
|
||||
return exchangeFunction.exchange(request).switchIfEmpty(NO_HTTP_CLIENT_RESPONSE_ERROR);
|
||||
}
|
||||
|
||||
private ClientRequest.Builder initRequestBuilder() {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.reactive.function.client;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -25,12 +26,15 @@ import org.mockito.Captor;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultWebClient}.
|
||||
@@ -160,7 +164,7 @@ public class DefaultWebClientTests {
|
||||
@Test
|
||||
public void apply() {
|
||||
WebClient client = builder()
|
||||
.apply(builder -> builder.defaultHeader("Accept", "application/json").defaultCookie("id", "123"))
|
||||
.apply(builder -> builder.defaultHeader("Accept", "application/json").defaultCookie("id", "123"))
|
||||
.build();
|
||||
client.get().uri("/path").exchange();
|
||||
|
||||
@@ -170,6 +174,12 @@ public class DefaultWebClientTests {
|
||||
verifyNoMoreInteractions(this.exchangeFunction);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void switchToErrorOnEmptyClientResponseMono() throws Exception {
|
||||
StepVerifier.create(builder().build().get().uri("/path").exchange())
|
||||
.expectErrorMessage("The underlying HTTP client completed without emitting a response.")
|
||||
.verify(Duration.ofSeconds(5));
|
||||
}
|
||||
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
Reference in New Issue
Block a user