From 24c46142c63ff0375e83374766903ac87c86d85d Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Fri, 24 Jun 2022 15:54:50 +0100 Subject: [PATCH] Add docs on exceptions for HTTP interface client Closes gh-28533 --- .../client/support/WebClientAdapter.java | 17 ++++++----- src/docs/asciidoc/integration.adoc | 28 ++++++++++++++++--- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java index c4f1ac590f..3ad530d4a6 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java @@ -25,7 +25,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; -import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.service.invoker.HttpClientAdapter; import org.springframework.web.service.invoker.HttpRequestValues; @@ -57,41 +56,41 @@ public final class WebClientAdapter implements HttpClientAdapter { @Override public Mono requestToVoid(HttpRequestValues requestValues) { - return toBodySpec(requestValues).exchangeToMono(ClientResponse::releaseBody); + return newRequest(requestValues).retrieve().toBodilessEntity().then(); } @Override public Mono requestToHeaders(HttpRequestValues requestValues) { - return toBodySpec(requestValues).retrieve().toBodilessEntity().map(ResponseEntity::getHeaders); + return newRequest(requestValues).retrieve().toBodilessEntity().map(ResponseEntity::getHeaders); } @Override public Mono requestToBody(HttpRequestValues requestValues, ParameterizedTypeReference bodyType) { - return toBodySpec(requestValues).retrieve().bodyToMono(bodyType); + return newRequest(requestValues).retrieve().bodyToMono(bodyType); } @Override public Flux requestToBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference bodyType) { - return toBodySpec(requestValues).retrieve().bodyToFlux(bodyType); + return newRequest(requestValues).retrieve().bodyToFlux(bodyType); } @Override public Mono> requestToBodilessEntity(HttpRequestValues requestValues) { - return toBodySpec(requestValues).retrieve().toBodilessEntity(); + return newRequest(requestValues).retrieve().toBodilessEntity(); } @Override public Mono> requestToEntity(HttpRequestValues requestValues, ParameterizedTypeReference bodyType) { - return toBodySpec(requestValues).retrieve().toEntity(bodyType); + return newRequest(requestValues).retrieve().toEntity(bodyType); } @Override public Mono>> requestToEntityFlux(HttpRequestValues requestValues, ParameterizedTypeReference bodyType) { - return toBodySpec(requestValues).retrieve().toEntityFlux(bodyType); + return newRequest(requestValues).retrieve().toEntityFlux(bodyType); } @SuppressWarnings("ReactiveStreamsUnusedPublisher") - private WebClient.RequestBodySpec toBodySpec(HttpRequestValues requestValues) { + private WebClient.RequestBodySpec newRequest(HttpRequestValues requestValues) { HttpMethod httpMethod = requestValues.getHttpMethod(); Assert.notNull(httpMethod, "HttpMethod is required"); diff --git a/src/docs/asciidoc/integration.adoc b/src/docs/asciidoc/integration.adoc index 9a3ed6cf5f..f80c4fa21c 100644 --- a/src/docs/asciidoc/integration.adoc +++ b/src/docs/asciidoc/integration.adoc @@ -371,7 +371,7 @@ methods for HTTP exchanges. You can then generate a proxy that implements this i and performs the exchanges. This helps to simplify HTTP remote access which often involves a facade that wraps the details of using the underlying HTTP client. -To start, declare an interface with annotated, HTTP exchange methods: +One, declare an interface with `@HttpExchange` methods: [source,java,indent=0,subs="verbatim,quotes"] ---- @@ -385,8 +385,7 @@ To start, declare an interface with annotated, HTTP exchange methods: } ---- -Now you create a proxy for the interface that performs the declared exchanges through -the `WebClient`: +Two, create a proxy that will perform the declared HTTP exchanges: [source,java,indent=0,subs="verbatim,quotes"] ---- @@ -396,7 +395,7 @@ the `WebClient`: RepositoryService service = factory.createClient(RepositoryService.class); ---- -An HTTP service interface can declare common attributes at the type level: +`@HttpExchange` is supported at the type level where it applies to all methods: [source,java,indent=0,subs="verbatim,quotes"] ---- @@ -504,6 +503,27 @@ TIP: You can also use any other async or reactive types registered in the `ReactiveAdapterRegistry`. +[[rest-http-interface-exceptions]] +==== Exception Handling + +By default, `WebClient` raises `WebClientResponseException` for 4xx and 5xx HTTP status +codes. To customize this, you can register a response status handler that applies to all +responses performed through the client: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + WebClient webClient = WebClient.builder() + .defaultStatusHandler(HttpStatusCode::isError, resp -> ...) + .build(); + + HttpServiceProxyFactory proxyFactory = + WebClientAdapter.createHttpServiceProxyFactory(webClient); +---- + +For more details and options, such as suppressing error status codes, see the Javadoc of +`defaultStatusHandler` in `WebClient.Builder`. + + [[jms]]