根据文档:
当远程客户端消失时,Servlet API 不会提供任何通知。因此,在流式传输到响应时,无论是通过SseEmitter还是反应类型,定期发送数据都很重要,因为如果客户端断开连接,写入就会失败。
这应该在调用
IOException
方法时表现为 SseEmitter::send()
,但是我使用的是 Spring + Embedded Tomcat 9.0.64 并且永远不会抛出此异常,因此不可能清理未使用的发射器。
我正在使用以下代码:
try {
emitter.send(SseEmitter.event()
.id(event.getId().toString())
.name("update")
.data(data)
);
} catch (Exception e) {
logger.info("Dead emitter detected. Removing...");
deadEmitters.add(emitter);
}
在这种情况下,永远不会触发异常。我是不是做错了什么?
我期望按照文档抛出异常。
另一个问题提出了类似的问题,但在这种情况下,记录的解决方案似乎根本不起作用。
将其发布给后代,因为似乎很少有关于该主题的明确记载:
SSE 没有提供客户端告诉服务器已断开连接的机制,TCP 也不包含此信息。为了正确,服务器必须尽可能长时间地发送响应(即直到服务器超时)。
正确的解决方案是每隔 X 秒在客户端上执行一次“心跳”调用,告诉服务器“是的,我还在这里”,然后清理未能及时报告回来的连接。
Websockets 不需要这个,因为它们默认提供了一种提供心跳(PING/PONG)的机制。
在我的例子中,使用 Springboot 2.7.18 并将外部 WAR 部署到 Tomcat 9,当尝试将事件发送到不再存在的客户端时,Springboot SseEmitter 将抛出 IOException。
尽管如此,我仍然对客户端实现了服务器端“ping”,以便快速清理过时的连接,而不是在您实际尝试发送内容时清理。