From 828fe395231fc2e7284769ac7c0250af66b15815 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Wed, 4 Dec 2019 18:19:18 +0000 Subject: [PATCH] Consistently use releaseBody in DefaultWebClient See gh-24125 --- .../function/client/ClientResponse.java | 8 +++++--- .../function/client/DefaultWebClient.java | 2 +- .../web/reactive/function/client/WebClient.java | 12 +++++++++--- src/docs/asciidoc/web/webflux-webclient.adoc | 17 ++++++----------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientResponse.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientResponse.java index cb7c9cd075..5c6eaa0cf1 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientResponse.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientResponse.java @@ -62,9 +62,11 @@ import org.springframework.web.reactive.function.BodyExtractor; *
  • {@link #toBodilessEntity()}
  • *
  • {@link #releaseBody()}
  • * - * You can use {@code bodyToMono(Void.class)} if no response content is - * expected. However keep in mind that if the response does have content, the - * connection will be closed and will not be placed back in the pool. + * You can also use {@code bodyToMono(Void.class)} if no response content is + * expected. However keep in mind the connection will be closed, instead of + * being placed back in the pool, if any content does arrive. This is in + * contrast to {@link #releaseBody()} which does consume the full body and + * releases any content received. * * @author Brian Clozel * @author Arjen Poutsma diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java index 866ba6e890..587c335dcb 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java @@ -532,7 +532,7 @@ class DefaultWebClient implements WebClient { private Mono drainBody(ClientResponse response, Throwable ex) { // Ensure the body is drained, even if the StatusHandler didn't consume it, // but ignore exception, in case the handler did consume. - return (Mono) response.bodyToMono(Void.class) + return (Mono) response.releaseBody() .onErrorResume(ex2 -> Mono.empty()).thenReturn(ex); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java index 93951bbb96..8bafb691fe 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java @@ -498,9 +498,15 @@ public interface WebClient { * .exchange() * .flatMapMany(response -> response.bodyToFlux(Person.class)); * - *

    NOTE: You must always use one of the body or - * entity methods of the response to ensure resources are released. - * See {@link ClientResponse} for more details. + *

    NOTE: Unlike {@link #retrieve()}, when using + * {@code exchange()}, it is the responsibility of the application to + * consume any response content regardless of the scenario (success, + * error, unexpected data, etc). Not doing so can cause a memory leak. + * See {@link ClientResponse} for a list of all the available options + * for consuming the body. Generally prefer using {@link #retrieve()} + * unless you have a good reason to use {@code exchange()} which does + * allow to check the response status and headers before deciding how or + * if to consume the response. * @return a {@code Mono} for the response * @see #retrieve() */ diff --git a/src/docs/asciidoc/web/webflux-webclient.adoc b/src/docs/asciidoc/web/webflux-webclient.adoc index 372255fcaf..2121f23c7e 100644 --- a/src/docs/asciidoc/web/webflux-webclient.adoc +++ b/src/docs/asciidoc/web/webflux-webclient.adoc @@ -496,17 +496,12 @@ Note that (unlike `retrieve()`), with `exchange()`, there are no automatic error [CAUTION] ==== -When using `exchange()`, you have to make sure that the body is always consumed or released, -even when an exception occurs (see <>). -Typically, you do this by invoking either `bodyTo*` or `toEntity*` on `ClientResponse` -to convert the body into an object of the desired type, but -you can also invoke `releaseBody()` to discard the body contents without consuming it or -`toBodilessEntity()` to get just the status and headers (while discarding the body). - -Finally, there is `bodyToMono(Void.class)`, which should only be used if no response content is -expected. -If the response does have content, the connection is closed and is not placed back in the pool, -because it is not left in a reusable state. +Unlike `retrieve()`, when using `exchange(), it is the responsibility of the application +to consume any response content regardless of the scenario (success, error, unexpected +data, etc). Not doing so can cause a memory leak. The Javadoc for `ClientResponse` lists +all the available options for consuming the body. Generally prefer using `retrieve()` +unless you have a good reason for using `exchange()` which does allow to check the +response status and headers before deciding how to or if to consume the response. ====