html - 为什么尝试使用 SSE 时 DeferredResult 在 setResult() 上结束

标签 html spring spring-mvc server-sent-events

我正在尝试实现一个由 Spring 提供支持的服务器发送事件 (SSE) 网页。我的测试代码执行以下操作:

浏览器使用EventSource(url)连接到服务器。 Spring 使用以下 Controller 代码接受请求:

@RequestMapping(value="myurl", method = RequestMethod.GET, produces = "text/event-stream")
@ResponseBody
public DeferredResult<String> subscribe() throws Exception {
    final DeferredResult<String> deferredResult = new DeferredResult<>();
    resultList.add(deferredResult);

    deferredResult.onCompletion(() -> {
        logTimer.info("deferedResult "+deferredResult+" completion");
        resultList.remove(deferredResult);
    });
    return deferredResult;
}

所以主要是将 DeferredResult 放入列表中并注册一个完成回调,以便我可以在完成时从列表中删除这个东西。

现在我有一个计时器方法,它将通过其 DeferredResults 定期向所有注册的“浏览器”输出当前时间戳。

@Scheduled(fixedRate=10000)
public void processQueues() {
    Date d = new Date();
    log.info("outputting to "+ LoginController.resultList.size()+ " connections");
    LoginController.resultList.forEach(deferredResult -> deferredResult.setResult("data: "+d.getTime()+"\n\n"));
}

数据被发送到浏览器,并且以下客户端代码起作用:

 var source = new EventSource('/myurl');
   source.addEventListener('message', function (e) {
            console.log(e.data);
            $("#content").append(e.data).append("<br>");
        });

现在的问题:

在计时器线程中每次调用 setResult() 时都会调用 DeferredResult 上的完成回调。因此,由于某种原因,连接在 setResult() 调用后关闭。浏览器中的 SSE 按照规范重新连接,然后再次发生同样的情况。因此,在客户端,我有一个轮询行为,但我想要一个保持开放的请求,我可以在同一个 DeferredResult 上一遍又一遍地推送数据。

我在这里错过了什么吗? DeferredResult 不能发送多个结果吗?我在计时器线程中设置了 10 秒的延迟,以查看请求是否仅在 setResult() 之后终止。因此,在浏览器中,请求保持打开状态,直到计时器推送数据,然后关闭。

感谢您对此的任何提示。还有一点需要注意:我向 tomcat 中的所有过滤器/servlet 添加了异步支持。

最佳答案

事实上 DeferredResult 只能设置一次(请注意 setResult 返回一个 bool 值)。它使用全部 Spring MVC 处理选项完成处理,即意味着您所知道的 Spring MVC 请求期间发生的情况或多或少保持不变,除了异步生成的返回值之外。

SSE 需要更集中的东西,即使用 HttpMessageConverter 将每个值写入响应。我已经为此创建了一张票 https://jira.spring.io/browse/SPR-12212 .

请注意,Spring 的 SockJS 支持确实有一个 SSE 传输,它负责一些额外的功能,例如带有 cookie 的跨域请求(对于 IE 很重要)。它还用于 WebSocket API 和 WebSocket 风格的消息传递(即使 WebSocket 在客户端或服务器端均不可用),从而完全抽象了 HTTP 长轮询的详细信息。

作为解决方法,您还可以使用 HttpMessageConverter 直接写入 Servlet 响应。

关于html - 为什么尝试使用 SSE 时 DeferredResult 在 setResult() 上结束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25880456/

相关文章:

json - JSON 使用什么内容类型 header ? "application/json; charset=utf-8 "还是 "application/json"?

java - 无法使用 weblogic 在 Spring MVC 项目中设置 session 值

php - 更新单元格所在ID

html - css 过渡动画不适用于 svg 路径的 "d' 属性更改

html - SEC7113 : CSS was ignored due to mime type mismatch

java - 是否建议使用Spring预定义的InitializingBean和DisposableBean回调?

mysql - Hibernate Spring 编码字符集错误 [UTF-8]

c# - 从 phonegap 应用程序的 MainPage.xaml.cs 切换 html 页面

java - Spring MVC + Hibernate 具有双向关系

spring - API 网关不起作用。抛出 java.net.UnknownHostException : failed to resolve