Consistently use releaseBody in DefaultWebClient

See gh-24125
This commit is contained in:
Rossen Stoyanchev 2019-12-04 18:19:18 +00:00
parent 3a48682226
commit 828fe39523
4 changed files with 21 additions and 18 deletions

View File

@ -62,9 +62,11 @@ import org.springframework.web.reactive.function.BodyExtractor;
* <li>{@link #toBodilessEntity()}</li>
* <li>{@link #releaseBody()}</li>
* </ul>
* 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

View File

@ -532,7 +532,7 @@ class DefaultWebClient implements WebClient {
private <T> Mono<T> 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<T>) response.bodyToMono(Void.class)
return (Mono<T>) response.releaseBody()
.onErrorResume(ex2 -> Mono.empty()).thenReturn(ex);
}

View File

@ -498,9 +498,15 @@ public interface WebClient {
* .exchange()
* .flatMapMany(response -&gt; response.bodyToFlux(Person.class));
* </pre>
* <p><strong>NOTE:</strong> 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.
* <p><strong>NOTE:</strong> 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()
*/

View File

@ -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 <<core.adoc#databuffers-using,Using DataBuffer>>).
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.
====