【发布时间】:2018-07-26 03:55:13
【问题描述】:
我一直在使用 webflux 启动器 (spring-boot-starter-webflux) 使用 spring-boot 2.0.0.RC1。我创建了一个返回无限通量的简单控制器。我希望发布者只有在有客户(订阅者)的情况下才可以工作。假设我有一个像这样的控制器:
@RestController
public class Demo {
@GetMapping(value = "/")
public Flux<String> getEvents(){
return Flux.create((FluxSink<String> sink) -> {
while(!sink.isCancelled()){
// TODO e.g. fetch data from somewhere
sink.next("DATA");
}
sink.complete();
}).doFinally(signal -> System.out.println("END"));
}
}
现在,当我尝试运行该代码并使用 Chrome 访问端点 http://localhost:8080/ 时,我可以看到数据。但是,一旦我关闭浏览器,while 循环就会继续,因为没有触发取消事件。 如何在关闭浏览器后立即终止/取消流式传输?
从这个answer我引用:
目前使用 HTTP,确切的背压信息不是 通过网络传输,因为 HTTP 协议不支持 这。如果我们使用不同的有线协议,这可能会改变。
我假设,由于 HTTP 协议不支持背压,这意味着也不会发出取消请求。
进一步调查,通过分析网络流量,显示只要我关闭浏览器,浏览器就会发送 TCP FIN。有没有办法配置 Netty(或其他东西),以便半关闭的连接会在发布者上触发取消事件,从而使 while 循环停止?
或者我是否必须编写类似于org.springframework.http.server.reactive.ServletHttpHandlerAdapter 的自己的适配器,并在其中实现自己的订阅者?
感谢您的帮助。
编辑:
如果没有客户端,将在尝试将数据写入套接字时引发IOException。正如您在stack trace 中看到的那样。
但这还不够好,因为可能需要一段时间才能准备好发送下一个数据块,因此检测消失的客户端需要相同的时间。正如Brian Clozel's answer 中所指出的,这是 Reactor Netty 中的一个已知问题。我尝试通过将依赖项添加到POM.xml 来改用Tomcat。像这样:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
虽然它取代了 Netty 并改用 Tomcat,但由于浏览器不显示任何数据,它似乎没有反应。但是,控制台中没有警告/信息/异常。 spring-boot-starter-webflux 这个版本 (2.0.0.RC1) 是否应该与 Tomcat 一起工作?
【问题讨论】:
标签: spring spring-boot project-reactor spring-webflux reactive-streams