Skip to content

Commit f5640cb

Browse files
committed
Add ClientResponse::releaseBody
See gh-23498
1 parent bc86965 commit f5640cb

File tree

4 files changed

+56
-5
lines changed

4 files changed

+56
-5
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientResponse.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,26 @@
4141

4242
/**
4343
* Represents an HTTP response, as returned by {@link WebClient} and also
44-
* {@link ExchangeFunction}. Provides access to the response status and headers,
45-
* and also methods to consume the response body.
44+
* {@link ExchangeFunction}. Provides access to the response status and
45+
* headers, and also methods to consume the response body.
4646
*
47-
* <p><strong>NOTE:</strong> When given access to a {@link ClientResponse},
47+
* <p><strong>NOTE:</strong> When using a {@link ClientResponse}
4848
* through the {@code WebClient}
4949
* {@link WebClient.RequestHeadersSpec#exchange() exchange()} method,
50-
* you must always use one of the body or toEntity methods to ensure resources
51-
* are released and avoid potential issues with HTTP connection pooling.
50+
* you have to make sure that the body is consumed or released by using
51+
* one of the following methods:
52+
* <ul>
53+
* <li>{@link #body(BodyExtractor)}</li>
54+
* <li>{@link #bodyToMono(Class)} or
55+
* {@link #bodyToMono(ParameterizedTypeReference)}</li>
56+
* <li>{@link #bodyToFlux(Class)} or
57+
* {@link #bodyToFlux(ParameterizedTypeReference)}</li>
58+
* <li>{@link #toEntity(Class)} or
59+
* {@link #toEntity(ParameterizedTypeReference)}</li>
60+
* <li>{@link #toEntityList(Class)} or
61+
* {@link #toEntityList(ParameterizedTypeReference)}</li>
62+
* <li>{@link #releaseBody()}</li>
63+
* </ul>
5264
* You can use {@code bodyToMono(Void.class)} if no response content is
5365
* expected. However keep in mind that if the response does have content, the
5466
* connection will be closed and will not be placed back in the pool.
@@ -132,6 +144,14 @@ public interface ClientResponse {
132144
*/
133145
<T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> elementTypeRef);
134146

147+
/**
148+
* Releases the body of this response.
149+
* @return a completion signal
150+
* @since 5.2
151+
* @see org.springframework.core.io.buffer.DataBufferUtils#release(DataBuffer)
152+
*/
153+
Mono<Void> releaseBody();
154+
135155
/**
136156
* Return this response as a delayed {@code ResponseEntity}.
137157
* @param bodyClass the expected response body type

spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,13 @@ public <T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> elementTypeRef) {
155155
return body(BodyExtractors.toFlux(elementTypeRef));
156156
}
157157

158+
@Override
159+
public Mono<Void> releaseBody() {
160+
return body(BodyExtractors.toDataBuffers())
161+
.map(DataBufferUtils::release)
162+
.then();
163+
}
164+
158165
@Override
159166
public <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType) {
160167
return WebClientUtils.toEntity(this, bodyToMono(bodyType));

spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/ClientResponseWrapper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ public <T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> elementTypeRef) {
118118
return this.delegate.bodyToFlux(elementTypeRef);
119119
}
120120

121+
@Override
122+
public Mono<Void> releaseBody() {
123+
return this.delegate.releaseBody();
124+
}
125+
121126
@Override
122127
public <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType) {
123128
return this.delegate.toEntity(bodyType);

spring-webflux/src/test/java/org/springframework/web/reactive/function/client/WebClientDataBufferAllocatingTests.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,25 @@ public void onStatusWithImmediateErrorAndBodyNotConsumed(String displayName, Dat
166166
});
167167
}
168168

169+
@ParameterizedDataBufferAllocatingTest
170+
public void releaseBody(String displayName, DataBufferFactory bufferFactory) {
171+
super.bufferFactory = bufferFactory;
172+
173+
this.server.enqueue(new MockResponse()
174+
.setResponseCode(200)
175+
.setHeader("Content-Type", "text/plain")
176+
.setBody("foo bar"));
177+
178+
Mono<Void> result = this.webClient.get()
179+
.exchange()
180+
.flatMap(ClientResponse::releaseBody);
181+
182+
183+
StepVerifier.create(result)
184+
.expectComplete()
185+
.verify(Duration.ofSeconds(3));
186+
}
187+
169188

170189
private void testOnStatus(Throwable expected,
171190
Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) {

0 commit comments

Comments
 (0)