我一直在使用spring-boot 2.0.0.RC1
和webflux starter (spring-boot-starter-webflux
)。我创建了一个简单的控制器,返回一个无限流。我希望只有在有客户端(订阅者)时,发布者才执行其工作。假设我有一个像下面这样的控制器:
@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循环会继续运行,因为没有取消事件被触发。如何在关闭浏览器后立即终止/取消流?
从这个答案中我引用:
目前使用HTTP时,确切的背压信息不会通过网络传输,因为HTTP协议不支持此操作。如果我们使用不同的线路协议,则可能会更改此设置。
我认为,由于HTTP协议不支持背压,这意味着也不会发出取消请求。
进一步调查,通过分析网络流量,显示浏览器在关闭后立即发送TCP FIN
。是否有一种方法可以配置Netty(或其他内容),以便半关闭的连接将触发发布者上的取消事件,使while循环停止?
还是我必须编写类似于org.springframework.http.server.reactive.ServletHttpHandlerAdapter
的自己的适配器,在其中实现自己的订阅者?
感谢任何帮助。
编辑:
如果没有客户端,则在尝试向套接字写数据时会引发IOException
。如你可以在堆栈跟踪中看到的那样。
但是这还不够好,因为在下一个数据块准备好发送之前可能需要一段时间,因此要检测已离开的客户端需要相同的时间。正如Brian Clozel在答案中指出的那样,这是Reactor Netty中已知的问题。我尝试通过将依赖项添加到POM.xml
来改用Tomcat。像这样:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
虽然它替换了Netty并使用Tomcat,但由于浏览器未显示任何数据,因此它似乎不是响应式的。 但是,控制台中没有警告/信息/异常。截至此版本(2.0.0.RC1
),spring-boot-starter-webflux
是否应该与Tomcat一起使用?