WebClient doesn't read response until request write is completed.

蓝咒 提交于 2020-12-04 00:38:17

问题


I'm trying to implement streaming proxy. I faced with the issue with WebClient from spring reactive.

Could anyone help me to understand Do I some wrong way or it's just a bug from WebClient side?

Stack:

reactor-netty 0.7.8.RELEASE

spring-boot 2.0.4.RELEASE

Desc:

I want to proxy a long stream to external service and then forward stream of responses to the requester. Streaming is happening using chunks (HTTP 1.1 Transfer-Encoding : chunked). External service processes every chunk and sends to the response result.

Expected behaviour:

WebClient should read every received part of response immediately.

Actual behaviour:

WebClient doesn't start process response until request write is completed.

Code:

return client
    .post()
    .header("Transfer-Encoding", "chunked")
//because I want to flush each received part
    .body((outputMessage, context) -> outputMessage.writeAndFlushWith(
        request.body(BodyExtractors.toDataBuffers())
               .map(dataBuffer -> Mono.just(dataBuffer))))
    .exchange()
    .flatMap(clientResponse -> {
      ServerResponse.BodyBuilder bodyBuilder = ServerResponse.status(clientResponse.statusCode());
      bodyBuilder.contentType(MediaType.APPLICATION_STREAM_JSON);

      return bodyBuilder.body((outputMessage, context) ->                                                        
          outputMessage.writeAndFlushWith(                                               
            clientResponse.body(BodyExtractors.toDataBuffers())                                                               
                          .map(dataBuffer -> Mono.just(dataBuffer))
                         ));}
);

回答1:


I've looked it up and it seems that by design, both Spring WebFlux's WebClient and Reactor Netty HttpClient are designed to first handle the request processing (sending the request body), and then reading the response body.

Other HTTP clients might allow this, but I think that in this case this is a way to link backpressure on both read/write operations and chain everything as a single reactive pipeline.

You might be looking for a message-oriented, bi-directionnal transport protocol with backpressure support. You can take a look at WebSockets (although you'll need to define your own message semantics there) or keep an eye on RSocket.

If you're just looking for an efficient reactive gateway, then Spring Cloud Gateway is your best bet since it's reactive all the way down and supports interesting additional features.

A few additional notes:

Spring WebFlux (at both client and server levels) uses Encoder and Decoder implementations, adapting to the message Content-Type. Some specific content-types, such as application/streaming+json or text/event-stream are implemented with streaming scenarios in mind. This means that encoders are writing messages as they come, separated with specific characters, and flushing on the network. Using regular media types such as application/octet-stream or application/json will not trigger that behavior. For those cases, proxies and intermediaries might buffer the message body and deliver bigger/smaller windows. This is why such mechanisms require a separator between messages and proper codecs.

As far as I understand, you're using HTTP 1.1 which is using a request/response mechanism - the HTTP spec doesn’t explicitly forbid te server from writing the response before reading the full request, but it does say that it has to read the full request body (or close the connection) no matter what. See https://tools.ietf.org/html/rfc7230#section-3.4

As always, you can request enhancements on https://jira.spring.io, although in this case, I think this is done by design.




回答2:


Just tested Jetty based WebClient implementation and it behaves as you expect. It can start reading response before all request content has been sent. It should have been released in Spring Framework 5.1 WebClient on Jetty new feature issue



来源:https://stackoverflow.com/questions/52113235/webclient-doesnt-read-response-until-request-write-is-completed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!