在需要实时向前端推送数据时,很多人第一反应是 WebSocket。但如果你的需求是"服务端单向推送 ",并不需要客户端向后端发送消息,那么 Spring 提供的 SseEmitter 会更加轻量、更易用,而且天然支持断线重连。本文总结了 SseEmitter 的核心原理、常见用法、注意事项以及生产实践经验。
一、SseEmitter 是什么?
SseEmitter 是 Spring MVC 提供的一个类,用于实现 基于 HTTP 的服务器单向推送(Server-Sent Events)。
它的特点包括:
- 单向推送(服务端 → 客户端)
- 基于标准 HTTP(不需要新协议)
- 支持自动重连(浏览器 EventSource 自带)
- 使用简单比 WebSocket 更轻,更适合消息通知类业务
适用场景:
- 消息提醒
- 实时状态更新
- 任务进度推送
- 监控数据刷新
二、基础用法示例
1. 创建 SSE 连接接口
java
@GetMapping("/sse/connect")
public SseEmitter connect() {
SseEmitter emitter = new SseEmitter(0L); // 0 表示不过期
// 在连接时发送一条消息
try {
emitter.send("连接成功");
} catch (Exception e) {
emitter.completeWithError(e);
}
return emitter;
}
注意:
new SseEmitter(0L)表示不超时,可减少长连接断开问题。- 返回后客户端会进入持续接收状态。
三、服务端主动推送消息
java
@Autowired
private List<SseEmitter> emitters = new CopyOnWriteArrayList<>();
@GetMapping("/sse/connect")
public SseEmitter connect() {
SseEmitter emitter = new SseEmitter(0L);
emitters.add(emitter);
emitter.onCompletion(() -> emitters.remove(emitter));
emitter.onTimeout(() -> emitters.remove(emitter));
return emitter;
}
@PostMapping("/sse/send")
public void sendMessage(@RequestParam String msg) {
for (SseEmitter emitter : emitters) {
try {
emitter.send(msg);
} catch (Exception e) {
emitter.complete();
}
}
}
关键点:
- 使用
CopyOnWriteArrayList保存所有连接 - 断开/异常时及时清理 emitter
- 推送时遍历所有 emitter
四、前端(浏览器)接收实现
js
const evtSource = new EventSource("/sse/connect");
evtSource.onmessage = function (event) {
console.log("收到消息:", event.data);
};
浏览器自带特性:断线自动重连,不需要你自己实现。
五、常见问题与解决方案
1. 前端收不到消息?(最常见)
原因可能是:
- 没有使用 UTF-8 文本格式
- 推送内容太大或太快
- 连接被代理/网关断开
解决:
java
emitter.send(SseEmitter.event().data("内容").id("1").name("msg"));
2. Nginx 或网关 1 分钟断开
这是行业常见问题,需要配置:
proxy_read_timeout 3600;
proxy_send_timeout 3600;
3. Spring 默认超时导致断开
务必使用:
java
new SseEmitter(0L);
4. 消息推送异常导致连接中断
一定要在异常时清理 emitter:
java
catch (Exception e) {
emitter.completeWithError(e);
}
六、生产实践建议
- 使用 心跳包 防止代理断开(比如每 20 秒发送一次空事件)
- 使用 CopyOnWriteArrayList 或 ConcurrentHashMap 存储用户连接
- 对每个发送操作包一层 try/catch,避免单个连接阻塞所有推送
- 数据频繁更新建议加上消息合并策略,避免推太快导致阻塞
总结
SseEmitter 是一个轻量但功能强大的实时推送工具,特别适合实时通知类业务。相比 WebSocket,它更简单,不需要复杂协议和框架即可实现稳定的实时消息推送。
如果你的业务属于"服务端单向推送",SseEmitter 往往是最优选择。