Skip to content

ClientResponse's body ignored on UnsupportedMediaTypeException [SPR-17054] #21592

Closed
@spring-projects-issues

Description

@spring-projects-issues

Denys Ivano opened SPR-17054 and commented

When remote service responses with Content-Type that can't be read by HttpMessageReader, an instance of UnsupportedMediaTypeException is being thrown (see BodyExtractors.readWithMessageReaders()). But ClientResponse's body is being ignored in this case.

From ClientResponse's Javadoc:

* <p><strong>NOTE:</strong> When given access to a {@link ClientResponse},
* through the {@code WebClient}
* {@link WebClient.RequestHeadersSpec#exchange() exchange()} method,
* you must always use one of the body or toEntity methods to ensure resources
* are released and avoid potential issues with HTTP connection pooling.
* 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.

So in order to release resources and avoid potential issues with HTTP connection pool, the response body must be consumed.

I've created a test that reproduces this issue:

@Test
public void shouldConsumeBodyOnUnsupportedMediaTypeException() {
    AtomicBoolean bodyConsumed = new AtomicBoolean();
    ExchangeFunction exchangeFunction = mock(ExchangeFunction.class);
    ClientResponse response = ClientResponse.create(HttpStatus.OK)
            .header(HttpHeaders.CONTENT_TYPE, "application/unknown")
//                .header(HttpHeaders.CONTENT_TYPE, "application/json")
            .body(Flux.defer(() -> {
                DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                return Flux.just("{\"name\": \"Hello World!\"}").
                        map(s -> {
                            bodyConsumed.set(true);
                            byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
                            return dataBufferFactory.wrap(bytes);
                        });
            }))
            .build();

    when(exchangeFunction.exchange(any())).thenReturn(Mono.just(response));

    WebClient webClient = WebClient.builder()
            .exchangeFunction(exchangeFunction)
            .build();

    Mono<String> result = webClient.get()
            .retrieve()
            .bodyToMono(TestResponse.class)
            .map(TestResponse::getName);

    StepVerifier.create(result)
            .expectError(UnsupportedMediaTypeException.class)
//                .expectNext("Hello World!")
//                .expectComplete()
            .verify(Duration.ZERO);

    assertTrue("Response body wasn't consumed", bodyConsumed.get());
}

private static class TestResponse {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Issue Links:

Referenced from: commits a410d90, d0ada56

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions