Java 通过SSE订阅的流量引发取消()事件

Java 通过SSE订阅的流量引发取消()事件,java,spring,spring-boot,project-reactor,spring-webflux,Java,Spring,Spring Boot,Project Reactor,Spring Webflux,我有一个SpringBoot2.0.0.M7+SpringWebFlux应用程序,其中我使用的是Thymeleaf Reactive 我注意到,在我的微服务上,当我在SSE模式(文本/事件流)下调用一个返回数据流的端点时,即使该数据流已被正确处理,也会在该数据流上发生cancel() 例如,下面是一个简单的控制器端点: @GetMapping(value = "/posts") public Flux<String> getCommunityPosts() { return

我有一个SpringBoot2.0.0.M7+SpringWebFlux应用程序,其中我使用的是Thymeleaf Reactive

我注意到,在我的微服务上,当我在SSE模式(文本/事件流)下调用一个返回数据流的端点时,即使该数据流已被正确处理,也会在该数据流上发生cancel()

例如,下面是一个简单的控制器端点:

@GetMapping(value = "/posts")
public Flux<String> getCommunityPosts() {
    return Flux.just("A", "B", "C").log("POSTS");
}
我们可以在onComplete之后注意到cancel事件。当我通过经典GET请求调用同一个端点时,我没有这种行为。我怀疑这个cancel事件使客户端事件源(javascript)抛出一个onError事件

是否为SSE特有的已知/通缉行为

问题更新

实际上,我在一些流上使用SSE,因为有时我需要事件源来获取JSON数据,而不是Thymeleaf已经处理过的HTML。我应该用另一种方式吗

我的实现基于此示例的最后一种方法:

然而,我可能没有在我之前的帖子中提供一些信息。我使用Tomcat服务器(带有M7的8.5.23),而不是Netty服务器。我强制使用Tomcat,包括以下Maven依赖项:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
当我在Tomcat服务器上运行相同的代码时,我遇到了取消问题:

2018-02-14 12:33:18.294  INFO 3088 --- [nio-8080-exec-3] reactor.Flux.ConcatMap.2 : onSubscribe(FluxConcatMap.ConcatMapImmediate)
2018-02-14 12:33:18.295  INFO 3088 --- [nio-8080-exec-3] reactor.Flux.ConcatMap.2 : request(1)
2018-02-14 12:33:19.295  INFO 3088 --- [     parallel-4] reactor.Flux.ConcatMap.2 : onNext(a)
2018-02-14 12:33:19.297  INFO 3088 --- [     parallel-4] reactor.Flux.ConcatMap.2 : request(1)
2018-02-14 12:33:20.302  INFO 3088 --- [     parallel-5] reactor.Flux.ConcatMap.2 : onNext(b)
2018-02-14 12:33:20.302  INFO 3088 --- [     parallel-5] reactor.Flux.ConcatMap.2 : request(1)
2018-02-14 12:33:21.306  INFO 3088 --- [     parallel-6] reactor.Flux.ConcatMap.2 : onNext(c)
2018-02-14 12:33:21.306  INFO 3088 --- [     parallel-6] reactor.Flux.ConcatMap.2 : request(1)
2018-02-14 12:33:21.307  INFO 3088 --- [     parallel-6] reactor.Flux.ConcatMap.2 : onComplete()
2018-02-14 12:33:21.307  INFO 3088 --- [nio-8080-exec-4] reactor.Flux.ConcatMap.2 : cancel()

这可能是Tomcat的问题,还是我做错了什么?

首先,我认为不应该将SSE用于有限流

当我创建控制器方法时,如:

@GetMapping(path = "/test", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@ResponseBody
public Flux<String> test() {
    return Flux.just("a", "b", "c").delayElements(Duration.ofSeconds(1)).log();
}
Flux
完成后,服务器将关闭连接,浏览器将自动重新连接。这将一次又一次地重播相同的序列


我在服务器上获得
cancel()
事件的唯一方法是在流期间关闭浏览器选项卡。

我根据您的代码用新信息编辑了我的初始帖子,我忘了提到我使用的是Tomcat服务器,而不是Netty服务器。实际上,当代码在Tomcat服务器上运行时,我只复制最后的cancel()事件。
2018-02-14 12:33:18.294  INFO 3088 --- [nio-8080-exec-3] reactor.Flux.ConcatMap.2 : onSubscribe(FluxConcatMap.ConcatMapImmediate)
2018-02-14 12:33:18.295  INFO 3088 --- [nio-8080-exec-3] reactor.Flux.ConcatMap.2 : request(1)
2018-02-14 12:33:19.295  INFO 3088 --- [     parallel-4] reactor.Flux.ConcatMap.2 : onNext(a)
2018-02-14 12:33:19.297  INFO 3088 --- [     parallel-4] reactor.Flux.ConcatMap.2 : request(1)
2018-02-14 12:33:20.302  INFO 3088 --- [     parallel-5] reactor.Flux.ConcatMap.2 : onNext(b)
2018-02-14 12:33:20.302  INFO 3088 --- [     parallel-5] reactor.Flux.ConcatMap.2 : request(1)
2018-02-14 12:33:21.306  INFO 3088 --- [     parallel-6] reactor.Flux.ConcatMap.2 : onNext(c)
2018-02-14 12:33:21.306  INFO 3088 --- [     parallel-6] reactor.Flux.ConcatMap.2 : request(1)
2018-02-14 12:33:21.307  INFO 3088 --- [     parallel-6] reactor.Flux.ConcatMap.2 : onComplete()
2018-02-14 12:33:21.307  INFO 3088 --- [nio-8080-exec-4] reactor.Flux.ConcatMap.2 : cancel()
@GetMapping(path = "/test", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@ResponseBody
public Flux<String> test() {
    return Flux.just("a", "b", "c").delayElements(Duration.ofSeconds(1)).log();
}
<script type="text/javascript">
    var testEventSource = new EventSource("/test");
    testEventSource.onmessage = function (e) {
        console.log(e);
    };
</script>
| onSubscribe([Fuseable] FluxOnAssembly.OnAssemblySubscriber)
| request(1)
| onNext(a)
| request(31)
| onNext(b)
| onNext(c)
| onComplete()
| onSubscribe([Fuseable] FluxOnAssembly.OnAssemblySubscriber)
| request(1)
| onNext(a)
| request(31)
| onNext(b)
| onNext(c)
| onComplete()