【发布时间】:2018-11-25 00:17:39
【问题描述】:
我有一个基于 Java 8 / Spring4 的 Web 应用程序,它使用服务器发送事件 (SSE) 向运行一些 Javascript 并更新进度条的基于浏览器的客户端报告长期运行进程的进度。在我的开发环境和我们的开发服务器上,SSE 近乎实时地到达客户端。我可以看到他们使用 Chrome 开发工具到达(连同他们的时间戳)并且进度条更新顺利。
但是,当我部署到我们的生产环境时,我观察到不同的行为。在长时间运行的过程完成之前,事件不会到达浏览器。然后它们都突然到达(根据开发工具,这些事件的时间戳都在几百毫秒内)。进度条在持续时间内停留在 0%,然后很快跳到 100%。同时,我的服务器日志告诉我事件是定期生成和发送的。
这是相关的服务器端代码:
public class LongRunningProcess extends Thread {
private SseEmitter emitter;
public LongRunningProcess(SseEmitter emitter) {
this.emitter = emitter;
}
public void run() {
...
// Sample event, representing 10% progress
SseEventBuilder event = SseEmitter.event();
event.name("progress");
event.data("{ \"progress\": 10 }"); // Hand-coded JSON
emitter.send(event);
...
}
}
@RestController
public class UploadController {
@GetMapping("/start")
public SseEmitter start() {
SseEmitter emitter = new SseEmitter();
LongRunningProcess process = new LongRunningProcess(emitter);
process.start();
return emitter;
}
}
这是相关的客户端 Javascript:
EventSource src = new EventSource("https://www.example.com/app/start");
src.addEventListener('progress', function(event) {
// Process event.data and update progress bar accordingly
});
我相信我的代码相当典型,并且在 DEV 中运行良好。但是,如果有人能看到问题,请告诉我。
问题可能与我们的生产服务器的配置有关。 DEV 和 PROD 都运行相同版本的 Tomcat。但是,其中一些是通过负载平衡器访问的(F5 在这种情况下)。几乎所有这些都支持 CDN(在我们的例子中是 Akamai)。此设置的某些部分是否会导致 SSE 被缓冲(或排队或缓存),这可能会产生我所看到的内容?
根据基础架构配置理念,我在响应标头中观察到以下内容。在开发环境中,我的浏览器接收到:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: Keep-Alive
Content-Type: text/event-stream;charset=UTF-8
Keep-Alive: timeout=15, max=99
Pragma: no-cache
Server: Apache
Transfer-Encoding: chunked
Via: 1.1 example.com
这是我对事件流的期望。内容长度未知的分块响应。在生产环境中,我的浏览器收到不同的东西:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Type: text/event-stream;charset=UTF-8
Content-Encoding: gzip
Content-Length: 318
Pragma: no-cache
Vary: Accept-Encoding
这里返回的内容具有已知长度并被压缩。我认为这不应该发生在事件流中。似乎有些东西正在将我的事件流转换为单个文件。关于如何弄清楚这是怎么回事的任何想法?
【问题讨论】:
-
你找到解决这个问题的方法了吗?我面临同样的问题。我的调查使我得出了同样的结论。禁用默认启用的 CompressingFilter 后,sse 按预期工作。我尝试绕过“文本/事件流”的过滤器,但没有帮助。
-
你在使用CompressingFilter吗?
-
@Mustafa 不,我没有使用
CompressingFilter。我还没有找到解决方案,但是我目前正在跟进可能的线索。如果这会导致解决方案,我会添加更多信息。 -
我切换到 tomcat 压缩,不再看到 SSE 的这个问题。
-
@Mustafa 你应该记录你所做的作为一个答案,以防其他人发现它有用。
标签: javascript java spring server-sent-events