在Web实时业务开发中,服务端消息推送是高频刚需场景,常见场景包含AI流式输出、系统消息通知、实时日志监控、IM即时通讯、数据大屏刷新等。目前主流的两种实时通信方案为 SSE(Server-Sent Events) 和WebSocket。
多数开发者在项目开发中存在选型误区:盲目使用WebSocket实现所有实时推送业务,导致项目冗余度提升、服务器资源浪费、维护成本增加。
本文将从协议原理、核心特性、场景差异、实战代码、生产避坑五个维度,系统性梳理SSE与WebSocket的区别,结合Spring Boot完整实战案例,帮助开发者在实际项目中精准选型。
1 核心概念与本质区别
1.1 SSE(Server-Sent Events)
SSE 是基于标准HTTP协议实现的单向长连接通信技术。客户端发起HTTP请求,服务端持续保持连接,主动向客户端推送数据流,客户端无法通过该连接向服务端传参。
核心特性:基于HTTP、单向通信、浏览器原生支持自动重连、仅支持文本数据、轻量低耗。
1.2 WebSocket
WebSocket 是独立的TCP通信协议,通过HTTP握手完成协议升级,建立全双工双向长连接。连接建立后,客户端与服务端可随时主动互传数据,无单次请求限制。
核心特性:独立TCP协议、双向通信、支持文本/二进制数据、低延迟、需手动实现心跳重连。
1.3 核心选型总结
- 仅需服务端单向推送、无客户端主动上报需求 → 优先使用 SSE
- 需要客户端与服务端双向实时交互 → 必须使用 WebSocket
2 底层原理与能力差异
2.1 协议层级差异
SSE:复用现有HTTP协议,无协议升级过程,兼容所有Web服务器、反向代理、跨域配置,零改造接入现有项目。
WebSocket:基于TCP实现独立通信协议,依赖HTTP完成握手升级,与HTTP协议相互独立,需要单独配置握手策略、跨域规则。
2.2 关键能力对比
- 通信方向:SSE 单向推送;WebSocket 全双工双向通信
- 重连机制:SSE 浏览器原生自动重连;WebSocket 需手动开发心跳检测、断线重连逻辑
- 数据格式:SSE 仅支持纯文本;WebSocket 支持文本、图片、文件等二进制数据
- 开发成本:SSE 零配置、开箱即用;WebSocket 需配置端点、处理异常、维护连接状态
- 资源开销:SSE 轻量低耗,适配高并发订阅场景;WebSocket 连接维护成本更高
3 精准适用场景划分
3.1 SSE 适用场景(单向推送)
所有仅需服务端主动推送、客户端无需频繁上报数据的业务场景:
- 大模型AI流式逐字输出、对话打字机效果
- 系统公告、站内消息、业务通知推送
- 运维实时日志、服务器监控、数据大屏动态刷新
- 股票行情、实时数据播报、进度条实时更新
3.2 WebSocket 适用场景(双向交互)
所有需要客户端、服务端高频双向实时交互的业务场景:
- 在线IM聊天室、即时消息通讯
- 直播弹幕、实时互动问答
- 在线联机游戏、多人协同编辑
- 实时指令控制、客户端状态高频上报
4 Spring Boot 实战代码落地
本章提供两套可直接编译运行的极简Demo,无冗余依赖,适配Spring Boot 3.x版本,可快速集成至生产项目。
4.1 SSE 单向推送实战
SSE 无需额外配置,基于Spring Web原生组件 SseEmitter 实现,开箱即用。
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.io.IOException; /** * SSE 单向实时推送实现 * 适配AI流式输出、消息通知、数据大屏等场景 * * @author CSDN * @date 2026 */ @RestController public class SsePushController { /** * 建立SSE长连接,持续推送实时数据 * 超时时间:30秒 */ @GetMapping("/sse/stream") public SseEmitter streamData() { SseEmitter emitter = new SseEmitter(30000L); // 异步线程模拟实时数据推送 new Thread(() -> { try { // 模拟10轮实时数据推送 for (int i = 1; i <= 10; i++) { emitter.send(SseEmitter.event() .name("real-time-msg") .data("实时推送数据:" + i)); Thread.sleep(1000); } // 推送完成,关闭连接 emitter.complete(); } catch (IOException | InterruptedException e) { // 异常终止连接 emitter.completeWithError(e); } }).start(); return emitter; } } |
前端原生JS调用代码:
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| javascript // 初始化SSE连接,浏览器自带自动重连 const eventSource = new EventSource("/sse/stream"); // 监听服务端推送消息 eventSource.onmessage = function (res) { console.log("接收实时数据:", res.data); }; // 连接异常自动重连 eventSource.onerror = function () { console.log("SSE连接异常,触发原生自动重连"); }; |
4.2 WebSocket 双向通信实战
WebSocket 需要配置端点扫描,实现连接监听、消息接收、双向应答逻辑。
第一步:WebSocket 核心配置类
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; /** * WebSocket 配置类 * 开启WebSocket端点自动扫描 */ @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } |
第二步:双向通信业务端点
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import jakarta.websocket.*; import jakarta.websocket.server.ServerEndpoint; import org.springframework.stereotype.Component; import java.io.IOException; /** * WebSocket 双向通信端点 * 支持客户端、服务端互发消息 */ @Component @ServerEndpoint("/ws/chat") public class WebSocketChatEndpoint { /** * 客户端连接建立回调 */ @OnOpen public void onOpen(Session session) { System.out.println("客户端建立连接,sessionId:" + session.getId()); } /** * 接收客户端消息并双向回复 */ @OnMessage public void onMessage(String msg, Session session) throws IOException { System.out.println("接收客户端消息:" + msg); // 服务端主动回复客户端,实现双向通信 session.getBasicRemote().sendText("服务端已接收消息:" + msg); } /** * 连接关闭回调 */ @OnClose public void onClose() { System.out.println("客户端断开连接"); } } |
前端双向通信调用代码:
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| javascript // 建立WebSocket双向长连接 let ws = new WebSocket("ws://localhost:8080/ws/chat"); // 监听服务端返回消息 ws.onmessage = function (e) { console.log("服务端回复:", e.data); }; // 客户端主动发送消息(双向通信核心能力) function sendMsg() { ws.send("客户端主动发起双向消息"); } |
5 技术对比汇总表
|------|---------------|-------------------|
| 对比维度 | SSE | WebSocket |
| 通信模式 | 单向推送(服务端→客户端) | 全双工双向通信 |
| 协议基础 | 基于HTTP长连接 | 独立TCP协议,需HTTP握手升级 |
| 重连机制 | 浏览器原生自动重连 | 需手动实现心跳重连 |
| 数据类型 | 仅支持文本数据 | 支持文本、二进制文件数据 |
| 开发难度 | 极低,原生支持、零配置 | 较高,需处理连接、异常、心跳 |
| 并发性能 | 轻量高并发,资源占用低 | 连接维护成本高,并发上限较低 |
6 生产环境避坑总结
结合线上落地经验,总结4条生产级最佳实践:
1. 杜绝过度开发:纯推送业务优先使用SSE,无需引入WebSocket,减少项目复杂度与服务器开销。
2. 禁止混合架构:双向交互业务不要使用「SSE+HTTP接口」拼接实现,架构混乱且稳定性差,直接使用WebSocket。
3. WebSocket必做心跳保活:无原生重连机制,线上必须实现心跳检测、超时断开、断线重连逻辑,规避静默断连问题。
4. SSE适配海量订阅场景:针对数据大屏、全局通知等多客户端订阅场景,SSE性能与稳定性显著优于WebSocket。
7 总结
SSE 是轻量化单向实时推送方案,优势在于简单、稳定、零成本、高并发,是纯推送业务的最优解。
WebSocket 是专业级双向实时通信方案,功能全面、延迟更低,专门解决双向交互场景。
两种技术无优劣之分,贴合业务场景的选型才是最优架构。开发者需根据业务交互模式、并发量级、维护成本综合判断,避免盲目选型。