Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebClient's handling of empty bodies seems broken [SPR-15679] #20238

Closed
spring-projects-issues opened this issue Jun 18, 2017 · 1 comment
Closed
Assignees
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

@spring-projects-issues spring-projects-issues commented Jun 18, 2017

Johannes Edmeier opened SPR-15679 and commented

When the WebClient retrieves an response without content (header content-length: 0 and without content-type header ) I would expect following things:

  1. when calling exchange() and doing ClientResponse#bodyToMono(Void.class) I expect that an empty Mono (that just completes) for the body is returned
  2. when calling retrieve().toEntity(Void.class) I expect a Mono with a ResponseEntity instance whose hasBody() returns false.

Both is currently not possible and throws an UnsupportedMediaTypeException

Tests:

  @Test
    public void nocontent_entity() {
        Mono<ResponseEntity<Void>> responseEntity = WebClient.create("http://localhost:8080")
                                                             .post()
                                                             .uri("/nocontent")
                                                             .retrieve()
                                                             .toEntity(Void.class);

        StepVerifier.create(responseEntity).assertNext(r -> {
            assertThat(r.hasBody()).isFalse();
            assertThat(r.getStatusCode().is2xxSuccessful()).isTrue();
        }).verifyComplete();
    }

    @Test
    public void nocontent_response() {
        Mono<ClientResponse> response = WebClient.create("http://localhost:8080").post().uri("/nocontent").exchange();

        StepVerifier.create(response).assertNext(r -> {
            assertThat(r.statusCode().is2xxSuccessful()).isTrue();
            StepVerifier.create(r.bodyToMono(Void.class)).verifyComplete();
        }).verifyComplete();
    }

Application

@SpringBootApplication
@RestController
public class WebfluxApplication {

	public static void main(String[] args) {
		SpringApplication.run(WebfluxApplication.class, args);
	}

	@PostMapping(path="/nocontent")
	public Mono<Void> nocontent() {
		return Mono.empty();
	}
}
java.lang.AssertionError: expectation "expectComplete" failed (expected: onComplete(); actual: onError(org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/octet-stream' not supported))

	at reactor.test.DefaultStepVerifierBuilder.failPrefix(DefaultStepVerifierBuilder.java:2114)
	at reactor.test.DefaultStepVerifierBuilder.fail(DefaultStepVerifierBuilder.java:2110)
	at reactor.test.DefaultStepVerifierBuilder.lambda$expectComplete$3(DefaultStepVerifierBuilder.java:199)
	at reactor.test.DefaultStepVerifierBuilder$SignalEvent.test(DefaultStepVerifierBuilder.java:1855)
	at reactor.test.DefaultStepVerifierBuilder$DefaultVerifySubscriber.onSignal(DefaultStepVerifierBuilder.java:1241)
	at reactor.test.DefaultStepVerifierBuilder$DefaultVerifySubscriber.onExpectation(DefaultStepVerifierBuilder.java:1186)
	at reactor.test.DefaultStepVerifierBuilder$DefaultVerifySubscriber.onError(DefaultStepVerifierBuilder.java:858)
	at reactor.core.publisher.Operators.error(Operators.java:195)
	at reactor.core.publisher.MonoError.subscribe(MonoError.java:51)
	at reactor.test.DefaultStepVerifierBuilder$DefaultStepVerifier.verify(DefaultStepVerifierBuilder.java:665)
	at reactor.test.DefaultStepVerifierBuilder$DefaultStepVerifier.verify(DefaultStepVerifierBuilder.java:639)
	at reactor.test.DefaultStepVerifierBuilder.verifyComplete(DefaultStepVerifierBuilder.java:508)
	at com.example.webflux.WebfluxApplicationTests.lambda$nocontent_response$1(WebfluxApplicationTests.java:46)
	at reactor.test.DefaultStepVerifierBuilder.lambda$consumeNextWith$1(DefaultStepVerifierBuilder.java:157)
	at reactor.test.DefaultStepVerifierBuilder$SignalEvent.test(DefaultStepVerifierBuilder.java:1855)
	at reactor.test.DefaultStepVerifierBuilder$DefaultVerifySubscriber.onSignal(DefaultStepVerifierBuilder.java:1241)
	at reactor.test.DefaultStepVerifierBuilder$DefaultVerifySubscriber.onExpectation(DefaultStepVerifierBuilder.java:1186)
	at reactor.test.DefaultStepVerifierBuilder$DefaultVerifySubscriber.onNext(DefaultStepVerifierBuilder.java:875)
	at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108)
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:170)
	at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108)
	at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:108)
	at reactor.core.publisher.FluxRetryPredicate$RetryPredicateSubscriber.onNext(FluxRetryPredicate.java:79)
	at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:122)
	at reactor.ipc.netty.channel.PooledClientContextHandler.fireContextActive(PooledClientContextHandler.java:84)
	at reactor.ipc.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:542)
	at reactor.ipc.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:125)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
	at java.lang.Thread.run(Thread.java:745)
	Suppressed: org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/octet-stream' not supported
		at org.springframework.web.reactive.function.BodyExtractors.lambda$readWithMessageReaders$16(BodyExtractors.java:237)
		at java.util.Optional.orElseGet(Optional.java:267)
		at org.springframework.web.reactive.function.BodyExtractors.readWithMessageReaders(BodyExtractors.java:233)
		at org.springframework.web.reactive.function.BodyExtractors.lambda$toMono$1(BodyExtractors.java:92)
		at org.springframework.web.reactive.function.client.DefaultClientResponse.body(DefaultClientResponse.java:78)
		at org.springframework.web.reactive.function.client.DefaultClientResponse.bodyToMono(DefaultClientResponse.java:98)
		... 34 more

Affects: 5.0 RC2

Issue Links:

  • #20260 WebClient fails to transform empty json array to emtpy flux ("is duplicated by")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants