当使用Spring WebClient时,由于HttpClientOperations接收到最后一个HTTP数据包,所以连接已关闭

时间:2018-07-19 13:13:37

标签: netty spring-webflux project-reactor

我正在使用Spring WebClient从我的服务器接收服务器发送事件(由Spring SSEEmitter发布)。它工作正常,但是由于某种原因,我的服务器会定期在新行中发布字符串“ 0”。发生这种情况时,WebClient将关闭连接。

我挖了一下并打开Spring调试,发现以下信息:

     +--------------------...+
     |  0  1  2  3  4  5  ... |
     | 30 0d 0a 0d 0a     ...-|0....           |

[reactor.ipc.netty.http.client.HttpClientOperations:218] Received last HTTP packet
[reactor.ipc.netty.http.client.HttpClient:71] - USER_EVENT: [Handler Terminated]
[reactor.ipc.netty.channel.ChannelOperationsHandler:218] - Disposing context reactor.ipc.netty.channel.PooledClientContextHandler@45a97ad8
[reactor.ipc.netty.channel.PooledClientContextHandler:218] - Releasing channel: 
[reactor.ipc.netty.resources.DefaultPoolResources:218] - Released, now 0 active connections
[reactor.ipc.netty.http.client.HttpClient:71] - READ COMPLETE
[reactor.ipc.netty.http.client.HttpClient:71] - READ COMPLETE
[reactor.ipc.netty.http.client.HttpClient:71] - CLOSE
[reactor.ipc.netty.http.client.HttpClient:71] - INACTIVE
[reactor.ipc.netty.http.client.HttpClient:71] - UNREGISTERED

很明显,WebClient内部使用Netty HttpClient,并且此客户端将字符串“ 0”视为“ lastHttpMessage”,然后关闭连接。

我的问题:

  • 为什么Netty将“ 0”视为http连接的结束。
  • 是否可以配置某事物来修改此行为。
  • WebClient只能使用Netty还是可以插入其他东西?到目前为止似乎不可能。

2 个答案:

答案 0 :(得分:1)

您看到的"0"是HTTP规范的一部分-当服务器发送HTTP分块响应时,大小为0的分块表示响应已完成。

我不认为我们可以在Netty中进行任何配置来更改此设置,也不认为应该这样做,因为这是HTTP的预期行为。

现在,我想知道为什么服务器首先发送它。您服务器上的Flux可能已到达尽头并正在发送onComplete信号,从而终止了响应。您的服务器实现中可能会有一些东西可以完成流。

您可以通过在管道中添加log Reactor运算符来查看服务器中正在发生的事情,以查看哪个部分正在发送onComplete信号。如果您有向我们展示的代码片段,我想您可以提出另一个问题,因为这个问题对于Spring社区已经非常有用,并且使其变得更加复杂也无济于事。

Spring Framework将通过WebClient支持其他客户端库-例如,Jetty客户端(请参阅问题SPR-15092。但是我认为使用其他客户端不会解决此问题,因为它符合HTTP,而不是特定于客户端的行为。

答案 1 :(得分:1)

我发现如果我使用“ repeat”,则连接完成后Flux将自动重新连接。真好!

final Flux<Object> stream = WebClient
            .create("http://localhost:8080/ssp")
            .get().uri("/common/v1/eventstream")
            .retrieve()
            .bodyToFlux(ServerSentEvent.class)
            .flatMap(e -> Mono.justOrEmpty(e.data()))
            .repeat();

    stream.subscribe(e -> System.out.println(e));