SSE(Server-Sent Events)是 HTML5 标准的一部分,它允许服务器通过 HTTP 长连接主动向浏览器推送数据。与我们熟悉的"请求-响应"模式不同,SSE 建立的是一条服务器到客户端的单向数据流通道——客户端发起一次请求后,连接保持打开,服务器可以持续不断地向客户端"推送"消息,直到连接被关闭。
在 WebSocket 大行其道的今天,SSE 常常被忽视,但它其实是很多"服务器推送"场景下更简单、更轻量的选择。
想对SSE有个快速的了解,可以 👉 点击此处在新页面中打开SSE演示动画
SSE 的核心魅力在于它完全基于标准 HTTP 协议,不需要像 WebSocket 那样进行协议升级(Upgrade)握手。客户端只需要发起一个普通的 GET 请求,服务器返回一个特殊的 Content-Type,连接就会保持打开状态。
服务器需要设置的响应头:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
SSE 传输的数据遵循一套简单的文本协议,每条消息以 \n\n(空行)作为结束标志。核心字段包括:
data: 这是一条消息内容
data: 支持多行
data: 每行都以 data: 开头
event: userLogin
data: {"user": "Alice"}
id: 12345
data: 带编号的消息,用于断线重连时定位
retry: 3000
data: 设置重连间隔为3秒
Last-Event-ID 请求头告知服务器浏览器原生提供了 EventSource API,使用起来非常简单:
const eventSource = new EventSource('/api/stream');
eventSource.onmessage = (event) => {
console.log('收到消息:', event.data);
};
eventSource.addEventListener('userLogin', (event) => {
const data = JSON.parse(event.data);
console.log('用户登录:', data.user);
});
eventSource.onerror = (err) => {
console.error('连接出错:', err);
// EventSource 会自动尝试重连,无需手动处理
};
EventSource 最贴心的一点是自动重连机制:一旦连接意外断开,浏览器会按照 retry 字段指定的时间自动重新发起连接,并携带 Last-Event-ID 请求头,让开发者可以在服务端实现"断点续传"式的消息补发。
app.get('/api/stream', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders();
const timer = setInterval(() => {
res.write(`data: ${JSON.stringify({ time: Date.now() })}\n\n`);
}, 1000);
req.on('close', () => {
clearInterval(timer);
res.end();
});
});
客户端 服务器
| |
|---- GET /api/stream ------------>|
| |
|<--- 200 OK ----------------------|
| Content-Type: text/event-stream
| |
|<--- data: message 1 -------------|
|<--- data: message 2 -------------|
|<--- data: message 3 -------------|
| ...(连接保持打开)........|
| |
| (若连接断开,浏览器自动重连, |
| 并携带 Last-Event-ID) |
|---- GET /api/stream ------------>|
| Last-Event-ID: 12345 |
|<--- data: message 4 -------------|
SSE 特别适合"服务器单向、高频地向客户端推送更新"的场景:
AI 对话流式输出:如 ChatGPT、Claude 等大模型应用中,文字逐字/逐词吐出的效果,正是通过 SSE 将模型生成的 token 流实时推送给前端
实时通知与提醒系统:如站内消息、系统公告、订单状态变更提醒
数据仪表盘 / 监控大屏:服务器指标、股票行情、体育赛事比分等需要持续刷新的只读数据展示
日志实时查看:CI/CD 流水线的构建日志、服务器运行日志的实时 tail
进度条与任务状态更新:文件上传处理进度、批量任务执行状态
社交媒体的实时动态流:如某用户的点赞数、评论数实时更新
EventSource API 几行代码即可用单向通信:SSE 只能服务器推送给客户端,客户端如果需要发数据回服务器,还是得依赖普通的 HTTP 请求。如果业务需要频繁的双向实时通信(如在线聊天、多人协作编辑、实时对战游戏),WebSocket 会是更合适的选择
连接数限制:浏览器对同一域名下的 HTTP/1.1 并发连接数有限制(通常是 6 个),如果页面中同时存在多个 SSE 连接,很容易触及上限,导致其他请求被阻塞(HTTP/2 下这个问题会有所缓解)
仅支持文本数据:SSE 只能传输 UTF-8 编码的文本,如果需要传输二进制数据(如音视频流),需要额外做 Base64 编码等处理,不如 WebSocket 原生支持二进制帧灵活
不支持旧版 IE:虽然现代浏览器都已支持,但如果项目仍需兼容 IE11 等老旧浏览器,需要引入 polyfill
某些反向代理/网关可能默认缓冲响应:如 Nginx 默认会对响应做缓冲,可能导致消息不能实时到达客户端,需要额外配置 proxy_buffering off 之类的选项
SSE 是"轻量级服务器推送"场景下被低估的一个技术选项。如果你的业务只需要服务器向客户端单向、持续地推送数据——尤其是像 AI 流式生成这类场景——SSE 往往比 WebSocket 更简单、更省心、也更容易部署和调试。而一旦涉及到需要客户端也频繁向服务器发送数据的双向实时交互,WebSocket 仍然是更合适的选择。技术选型的关键,永远是先看清业务的真实通信模式,再决定用什么协议去实现它。
No comments yet. Be the first!