使用Spring Boot实现Server-Sent Events(SSE)实时推送
什么是SSE?
Server-Sent Events(SSE) 是一种基于HTTP的服务器向客户端单向实时推送数据的技术。与WebSocket不同,SSE仅支持服务器到客户端的单向通信,适用于实时通知、股票行情、新闻推送等场景。
核心特性:
- 基于HTTP协议,兼容现有基础设施
- 支持自动重连
- 轻量级,使用简单
- 默认支持文本数据格式
一、快速搭建Spring Boot SSE服务
1. 创建项目
通过Spring Initializr创建项目,选择依赖:
- Spring Web(用于Web端点)
2. 实现SSE控制器
java
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@RestController
public class SSEController {
private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>();
// 客户端连接端点
@GetMapping(path = "/connect", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter connect(@RequestParam String userId) {
SseEmitter emitter = new SseEmitter(60_000L); // 超时时间60秒
// 注册清理回调
emitter.onCompletion(() -> emitters.remove(userId));
emitter.onTimeout(() -> emitters.remove(userId));
emitters.put(userId, emitter);
return emitter;
}
// 消息推送方法(可在Service中调用)
public void sendEvent(String userId, String message) {
SseEmitter emitter = emitters.get(userId);
if (emitter != null) {
try {
emitter.send(SseEmitter.event()
.data(message)
.name("custom-event")); // 自定义事件名称
} catch (IOException e) {
emitters.remove(userId);
}
}
}
}
二、客户端实现
HTML页面示例:
html
<!DOCTYPE html>
<html>
<body>
<div id="messages"></div>
<script>
const eventSource = new EventSource('http://localhost:8080/connect?userId=123');
// 监听默认消息
eventSource.onmessage = (e) => {
document.getElementById('messages').innerHTML += e.data + '<br>';
};
// 监听自定义事件
eventSource.addEventListener('custom-event', (e) => {
console.log('Custom event:', e.data);
});
</script>
</body>
</html>
三、进阶功能实现
1. 广播消息
java
public void broadcast(String message) {
emitters.forEach((id, emitter) -> {
try {
emitter.send(message);
} catch (IOException e) {
emitters.remove(id);
}
});
}
2. 发送结构化数据(JSON)
java
emitter.send(SseEmitter.event()
.data(new MyDataObject("value"), MediaType.APPLICATION_JSON)
.id("event-123")
.reconnectTime(5000));
3. 心跳机制(防止连接超时)
java
@Scheduled(fixedRate = 30_000)
public void sendHeartbeat() {
emitters.forEach((id, emitter) -> {
try {
emitter.send(SseEmitter.event().comment("heartbeat"));
} catch (IOException ignored) {}
});
}
四、注意事项
-
连接管理
- 使用
ConcurrentHashMap
存储连接 - 及时移除已关闭的连接
- 设置合理的超时时间(默认:30秒)
- 使用
-
跨域问题
java@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/connect") .allowedOrigins("*"); } }
-
性能优化
- 调整Tomcat线程池配置
- 考虑使用异步处理(
@Async
)
五、SSE vs WebSocket
特性 | SSE | WebSocket |
---|---|---|
协议 | HTTP | WS/TCP |
通信方向 | 单向(服务器→客户端) | 双向 |
数据格式 | Text/Event-Stream | 二进制/自定义 |
自动重连 | 支持 | 需手动实现 |
浏览器兼容性 | 除IE外主流浏览器 | 现代浏览器 |
总结
SSE是实现服务器推送的高效解决方案,适用于需要实时更新但不需要双向通信的场景。结合Spring Boot的SseEmitter
,开发者可以快速构建实时功能。完整示例代码已上传至GitHub仓库。
扩展阅读:
通过本文,读者可以快速掌握SSE的核心实现,并根据实际需求扩展功能。建议根据具体场景选择合适的实时通信方案。