【发布时间】:2014-11-10 21:25:33
【问题描述】:
我正在尝试实现一个由 Spring 提供支持的服务器发送事件 (SSE) 网页。我的测试代码执行以下操作:
浏览器使用 EventSource(url) 连接到服务器。 Spring 使用以下控制器代码接受请求:
@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 中添加了异步支持。
【问题讨论】:
标签: html spring spring-mvc server-sent-events