You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring SseEmitter超时机制疑问及超时后报错问题咨询

Spring SseEmitter超时机制疑问及超时后报错问题咨询

老哥,我来帮你理清楚SseEmitter的超时机制和你遇到的报错问题~

一、先明确SseEmitter超时参数的真实含义

你之前对超时的两种理解,正确的是第一种:空闲超时。new SseEmitter(30000L)里的30000L是指连接的最大空闲时长,具体逻辑是:

  • 如果连接建立后,服务器在30秒内没有调用sseEmitter.send()给客户端发任何数据,就会触发onTimeout回调并关闭连接;
  • 只要期间有调用send()发送数据,超时计时器就会被重置,连接不会因为“到点就关”而关闭。你之前以为的“不管有没有send,30秒后必关”是误解哦。

二、你遇到的超时后报错原因分析

看你的代码,后端设置了10秒超时,但又用定时任务每秒发一次数据,理论上不该触发超时。不过你说超时到了就报错,大概率是你的错误处理逻辑有问题:
当onTimeout触发后,这个SseEmitter实例已经处于“超时完成”的状态了,你在onError里还尝试调用sseEmitter.send(),并把它重新放回sseEmitterMap,这时候调用send()必然会抛出IOException——因为已经超时的SseEmitter是无法再发送数据的。

三、修正方案(结合你的代码)

1. 正确处理超时回调

超时后应该发送重连提示(如果需要),然后完成连接并从map中移除失效的实例:

sseEmitter.onTimeout(() -> {
    System.out.println("连接超时,时间:" + Calendar.getInstance().getTime());
    try {
        // 给客户端发超时事件,指定重连间隔
        sseEmitter.send(SseEmitter.event()
                .id(uid)
                .name("timeout")
                .data("连接超时,即将重连")
                .reconnectTime(3000));
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 标记连接完成,清理资源
    sseEmitter.complete();
    sseEmitterMap.remove(uid);
});

2. 修正错误回调逻辑

出错的SseEmitter已经失效,不能再复用,应该直接清理并提示客户端重连:

sseEmitter.onError(throwable -> {
    System.err.println("SSE连接出错:" + throwable.getMessage());
    // 先移除失效的实例,避免后续调用出错
    sseEmitterMap.remove(uid);
    try {
        // 发送错误事件,通知客户端重连
        sseEmitter.send(SseEmitter.event()
                .id(uid)
                .name("error")
                .data("连接出错,即将重连")
                .reconnectTime(3000));
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 标记连接以错误结束
    sseEmitter.completeWithError(throwable);
});

3. 额外提醒:前端重连逻辑

EventSource默认会自动尝试重连,你设置的reconnectTime会告诉前端多久后重连。如果需要更灵活的重连控制,也可以在前端的onerror或onclose里手动处理重连逻辑。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 08:54:30