Spring Boot中SSE推送核心是服务端用SseEmitter保持HTTP长连接、以text/event-stream格式发送事件,客户端用EventSource自动接收解析;它轻量单向,适用于通知、日志等场景,需注意超时设置、响应头、反向代理配置及 emitter 生命周期管理。

Spring Boot 中实现 Server-Sent Events(SSE)推送,核心是让服务端保持 HTTP 连接长开,以 text/event-stream 方式持续写入事件数据,客户端用 EventSource 自动接收解析。它比 WebSocket 更轻量,适合单向、低频、实时性要求不极端的场景(如通知、日志流、状态更新)。
服务端:用 SseEmitter 返回事件流
Spring MVC 原生支持 SSE,关键在于返回 SseEmitter 对象,并在后台线程中调用其 send() 方法推送事件。
- 控制器方法返回类型必须是 SseEmitter(不能是 ResponseEntity
,否则响应头可能被覆盖) - 建议设置超时时间(如 30 秒),避免连接无限挂起;超时后 emitter 自动完成,可捕获异常重试或清理资源
- 每次 send() 可传入 SseEventBuilder(用 SseEmitter.event() 构建),支持设置 event、id、data、retry 等字段
- 注意:SseEmitter 不是线程安全的,每个请求应创建独立实例;若需广播给多个客户端,需自行维护 emitter 集合并同步发送
示例代码:
@GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter handleEvents() {
SseEmitter emitter = new SseEmitter(30_000L); // 30秒超时
<pre class="brush:php;toolbar:false;">// 模拟异步推送(实际中可来自 MQ、定时任务、WebSocket 入口等)
CompletableFuture.runAsync(() -> {
try {
for (int i = 0; i <p>}</p>客户端:用 EventSource 接收并监听事件
浏览器原生支持 EventSource API,自动重连、解析 event/data/id/retry 字段,无需额外库。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- new EventSource('/events') 即可建立连接;路径需与后端控制器一致
- 监听 onmessage(默认事件)、onerror、onopen,也可监听自定义 event 名(如 addEventListener('message', ...)
- 服务端返回的 data 字段会自动去除前缀 "data:" 并合并多行(用 \n\n 分隔),最终以字符串形式传入回调
- 若需携带结构化数据,推荐 JSON 字符串(如 data: {"type":"update","value":100}),客户端用 JSON.parse() 解析
示例 JS:
const eventSource = new EventSource("/events");
<p>eventSource.onopen = () => console.log("SSE 连接已建立");
eventSource.onerror = (err) => console.error("SSE 错误:", err);
eventSource.addEventListener("message", (e) => {
console.log("收到消息:", e.data); // e.data 是字符串
});</p><p>// 若服务端发的是 JSON,可这样处理:
eventSource.addEventListener("update", (e) => {
const data = JSON.parse(e.data);
console.log("更新内容:", data);
});</p>
关键细节与注意事项
SSE 表面简单,但实际部署中几个点容易出问题:
- 响应头必须正确:Content-Type 必须为 text/event-stream;Spring Boot 默认已设好,但若用了拦截器或全局过滤器,可能覆盖或丢失该头
-
Tomcat/Jetty 默认禁用长连接缓冲:某些嵌入式容器会缓存响应体,导致事件延迟发出。可在 application.yml 中关闭输出缓冲:
# Spring Boot 3.x+(Tomcat)server.tomcat.connection-timeout=20000<br>server.tomcat.redirect-context-root=false
更稳妥做法是手动设置 response.flushBuffer() —— 但 SseEmitter 内部已处理,通常无需干预 - 反向代理(Nginx)需配置超时和 header 透传:默认 60 秒断连,需增加 proxy_read_timeout;并显式允许 X-Accel-Buffering: no 和 Content-Type 透传
- 不支持 IE:EventSource 是现代浏览器特性(Chrome 6+、Firefox 6+、Edge 17+),IE 完全不支持,需降级方案(如轮询)
进阶:广播与生命周期管理
若需向所有在线客户端广播(如系统通知),不能依赖单个 SseEmitter。常见做法是:
- 用 CopyOnWriteArraySet
存储活跃连接,并在 Controller 中注册/移除 - 注册时设置 completionCallback(emitter.onCompletion())和 timeoutCallback,及时清理失效 emitter
- 广播时遍历集合 send(),对已 complete 或异常的 emitter 调用 remove();注意 send() 是阻塞的,大量客户端时建议异步分批推送
- 避免内存泄漏:每个 emitter 应绑定用户标识(如 token 或 session ID),配合登录态校验,防止恶意长连耗尽资源
不复杂但容易忽略。把 emitter 生命周期管住、响应头保准、代理配对,SSE 就能稳稳跑起来。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










