【简单易懂】SSE 和 WebSocket(Java版)
一、前言
- SSE(Server-Sent Events) 和 WebSocket 是两种用于实现实时通信的 Web 技术;
- 但它们在设计、用途和实现方式上有显著区别。
二、SSE(Server-Sent Events)
-
定义:基于 HTTP 的单向通信协议,允许服务器主动向客户端推送数据。
-
特点:
- 单向通信:仅支持服务器 → 客户端的单向数据推送。
- 基于 HTTP:使用简单,无需额外协议,兼容现有 HTTP 基础设施。
- 自动重连:内置断线重连机制,客户端会自动尝试重新连接。
- 轻量级:数据格式为纯文本(如 text/event-stream),适合推送简单数据,如新闻、股价。
-
适用场景:
- 实时通知(如新闻、天气更新)。
- 服务器主导的实时数据推送(如日志流、进度条更新)。
-
局限性:
- 不支持客户端向服务器发送消息。
- 部分旧浏览器(如 IE)不支持。
三、WebSocket
- 定义:基于 TCP 的全双工通信协议,支持客户端与服务器双向实时通信。
- 特点:
- 双向通信:客户端和服务端可以同时发送和接收数据。
- 独立协议:通过 HTTP 升级握手建立连接(ws:// 或 wss://),之后脱离 HTTP 独立运行。
- 低延迟:持久化连接,适合高频交互场景(如聊天、游戏)。
- 支持二进制数据:可传输文本或二进制数据(如图片、音频)。
- 适用场景:
- 实时聊天、协作工具。
- 多人在线游戏、实时交易系统。
- 局限性:
- 实现复杂度较高(需处理连接状态、心跳检测等)。
- 需要服务器和客户端同时支持 WebSocket 协议。
四、核心区别对比
五、代码示例(基于Java的Spring Boot)
1、SSE
A.服务端代码
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;@RestController
public class SseController {@GetMapping(path = "/sse-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter streamEvents() {SseEmitter emitter = new SseEmitter(60_000L); // 超时时间 60 秒// 模拟实时数据推送(实际可能从数据库或外部服务获取)new Thread(() -> {try {for (int i = 0; i < 10; i++) {SseEmitter.SseEventBuilder event = SseEmitter.event().data("SSE 数据 - " + i) // 推送的数据.id(String.valueOf(i)) // 事件 ID(可选).name("sse-event"); // 事件名称(可选)emitter.send(event);Thread.sleep(1000); // 间隔 1 秒}emitter.complete(); // 完成推送} catch (Exception e) {emitter.completeWithError(e); // 异常处理}}).start();return emitter;}
}
B.客户端代码(JavaScript)
const eventSource = new EventSource('/sse-stream');
eventSource.onmessage = (e) => {console.log("收到 SSE 数据:", e.data);
};
eventSource.onerror = (e) => {console.error("SSE 连接错误:", e);
};
C.关键点
-
服务端使用 SseEmitter 发送事件流。
-
客户端通过 EventSource 监听数据。
2、WebSocket
A. [服务端]依赖引入(pom.xml)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
B. [服务端]WebSocket配置类
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new MyWebSocketHandler(), "/ws").setAllowedOrigins("*"); // 允许跨域}
}
C. [服务端]WebSocket处理器
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;public class MyWebSocketHandler extends TextWebSocketHandler {@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {// 连接建立时触发session.sendMessage(new TextMessage("服务端:连接成功!"));}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {// 收到客户端消息时触发String clientMsg = message.getPayload();System.out.println("收到客户端消息: " + clientMsg);// 回复客户端session.sendMessage(new TextMessage("服务端回复: " + clientMsg));}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) {// 连接关闭时触发System.out.println("WebSocket 连接关闭");}
}
D. 客户端测试(JavaScript)
const socket = new WebSocket('ws://localhost:8080/ws');// 连接成功
socket.onopen = () => {console.log("WebSocket 连接已建立");socket.send("Hello WebSocket!");
};// 接收消息
socket.onmessage = (e) => {console.log("收到消息:", e.data);
};// 连接关闭
socket.onclose = () => {console.log("WebSocket 连接已关闭");
};
E.关键点
- 服务端通过 WebSocketHandler 处理连接和消息。
- 客户端使用浏览器原生 WebSocket API 通信。
六、使用建议 / 如何选择
- 选择 SSE:
- 只需服务器向客户端推送数据(如实时通知、数据监控)。
- 希望快速实现且兼容现有 HTTP 服务。
- 选择 WebSocket:
- 需要双向实时交互(如聊天室、在线游戏)。
- 对延迟敏感或需传输二进制数据。
七、总结
- SSE 适合单向服务器推送场景,简单且对开发友好。
- WebSocket 适合双向高频通信,性能更优但实现复杂。
- 两者可结合使用(例如:用 SSE 接收通知,用 WebSocket 处理交互)。
- 根据实际需求选择技术方案。