Spring Boot 整合 SSE(Server-Sent Events)
1、简述
SSE(Server-Sent Events)是一种基于HTTP协议的单向通信机制,允许服务器向浏览器持续发送实时更新。与WebSocket不同,SSE更简单,使用HTTP/1.1协议即可,不需要额外的协议升级。它通过简单的文本流格式(data: ...\n\n
)传输事件,支持自定义事件类型和重连机制。
SSE与其他技术的对比
技术 | 协议 | 双向通信 | 复杂度 | 适用场景 |
---|---|---|---|---|
SSE | HTTP | 单向 | 低 | 服务器主动推送(如通知) |
WebSocket | WS | 双向 | 高 | 实时聊天、游戏 |
长轮询 | HTTP | 半双工 | 中 | 兼容性要求高的场景 |
SSE的特点:
- 自动重连:客户端在连接断开时会自动尝试重新连接。
- 轻量级协议:事件流格式简单,无需额外解析库。
- 浏览器原生支持:现代浏览器通过
EventSource
API直接使用。
2、Spring Boot 中的SSE实现
2.1 添加依赖与配置
验证Spring Boot版本兼容性:确保使用Spring Boot 2.2+版本以获得更好的异步支持。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
</parent>
2.2 实现后端接口
代码深度解析:
- 使用
Stream.generate
生成数据流,但需注意无限流会导致线程阻塞,推荐结合异步线程池。 - 添加事件ID和重试机制(增强SSE规范支持):
@GetMapping(value = "/sse/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream() {
return Flux.interval(Duration.ofSeconds(1))
.map(sequence -> "id: " + sequence + "\n"
+ "data: " + LocalTime.now() + "\n\n")
.take(10);
}
2.3 超时与异常处理
精细化配置:
- 通过
SseEmitter
设置超时回调,记录未完成的连接:
emitter.onTimeout(() -> {
log.warn("SSE连接超时:{}", emitter);
emitters.remove(emitter);
});
- 全局异常处理:使用
@ExceptionHandler
捕获IOException
,避免连接中断导致服务不可用。
2.4 前端实现优化
增强健壮性:
- 监听特定事件类型并处理重连:
eventSource.addEventListener("customEvent", function(e) {
console.log("自定义事件数据:", e.data);
});
eventSource.onerror = function() {
setTimeout(() => new EventSource('/sse/stream'), 5000); // 5秒后重连
};
- 添加心跳检测:服务器定期发送注释行(
:keep-alive\n
)防止代理超时。
3、高级实践
3.1 结合Spring Security实现鉴权
保护SSE端点:
@GetMapping("/sse/private-stream")
public SseEmitter privateStream(Authentication authentication) {
if (authentication == null) {
throw new SecurityException("未授权访问");
}
return ssePushService.subscribe();
}
Token验证:前端在初始化EventSource
时携带Token:
new EventSource('/sse/private-stream?token=xxxx');
3.2 分布式场景下的解决方案
使用消息队列广播事件(以Redis Pub/Sub为例):
- 引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 订阅Redis频道并推送消息:
@Bean
public MessageListenerAdapter redisListener(SsePushService pushService) {
return new MessageListenerAdapter((message, channel) ->
pushService.pushMessage(message.toString()));
}
3.3 性能监控与调优
- 监控连接数:通过
/actuator/metrics/sse.emitters
端点(需集成Actuator)。 - 背压控制:使用Project Reactor的
Flux
处理背压,避免服务器过载。
4、注意事项(增强版)
-
浏览器兼容性:
- IE完全不支持,可通过
polyfill
(如eventsource
库)降级为长轮询。 - 移动端浏览器需测试网络切换(如4G/WiFi)对连接的影响。
- IE完全不支持,可通过
-
消息格式规范:
- 每条消息以
data:
开头,结尾必须有两个换行符。 - 发送JSON数据需转义换行符:
data: {\"time\": \"12:00\"}\n\n
。
- 每条消息以
-
安全加固:
- 启用HTTPS防止中间人攻击。
- 限制每IP连接数,防止DDoS攻击。
5、实战案例:实时日志监控系统
架构设计
- 日志收集:Filebeat监听日志文件变动。
- 消息中转:Kafka接收日志并缓存。
- SSE推送:Spring Boot消费Kafka消息并广播。
关键代码
@KafkaListener(topics = "logs")
public void handleLog(String logMessage) {
ssePushService.pushMessage(logMessage);
}
6、调试与测试技巧
- 使用Curl测试SSE:
curl -N http://localhost:8080/sse/stream
- 浏览器开发者工具:
- 网络面板查看
EventStream
分帧详情。 - 控制台调试
EventSource
事件监听。
- 网络面板查看
延伸阅读: