SseEmitter 在客户端断开连接时不会抛出 IOException

问题描述 投票:0回答:2

根据文档

当远程客户端消失时,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);
}

在这种情况下,永远不会触发异常。我是不是做错了什么?

我期望按照文档抛出异常。

另一个问题提出了类似的问题,但在这种情况下,记录的解决方案似乎根本不起作用。

spring spring-mvc
2个回答
2
投票

将其发布给后代,因为似乎很少有关于该主题的明确记载:

SSE 没有提供客户端告诉服务器已断开连接的机制,TCP 也不包含此信息。为了正确,服务器必须尽可能长时间地发送响应(即直到服务器超时)。

正确的解决方案是每隔 X 秒在客户端上执行一次“心跳”调用,告诉服务器“是的,我还在这里”,然后清理未能及时报告回来的连接。

Websockets 不需要这个,因为它们默认提供了一种提供心跳(PING/PONG)的机制。


0
投票

在我的例子中,使用 Springboot 2.7.18 并将外部 WAR 部署到 Tomcat 9,当尝试将事件发送到不再存在的客户端时,Springboot SseEmitter 将抛出 IOException。
尽管如此,我仍然对客户端实现了服务器端“ping”,以便快速清理过时的连接,而不是在您实际尝试发送内容时清理。

© www.soinside.com 2019 - 2024. All rights reserved.