JavaScript Server-Sent Events
外观
Server-Sent Events (SSE) 是一种基于 HTTP 的轻量级协议,允许服务器向客户端单向推送实时数据。与 WebSocket 不同,SSE 仅支持服务器到客户端的单向通信,但实现简单且兼容标准 HTTP 协议。
概述[编辑 | 编辑源代码]
SSE 通过持久的 HTTP 连接实现服务器推送,适用于需要实时更新但无需客户端频繁发送数据的场景(如新闻推送、股票行情、日志监控等)。
核心特性[编辑 | 编辑源代码]
- 单向通信:服务器 → 客户端
- 文本协议:基于纯文本(如 JSON、XML)
- 自动重连:客户端在连接断开时会尝试重新连接
- 事件流格式:遵循 `text/event-stream` MIME 类型
基本用法[编辑 | 编辑源代码]
客户端实现[编辑 | 编辑源代码]
使用 JavaScript 的 `EventSource` API 监听服务器事件:
// 创建 EventSource 对象,指定服务器端点
const eventSource = new EventSource('/sse-endpoint');
// 监听默认事件(未命名事件)
eventSource.onmessage = (event) => {
console.log('收到数据:', event.data);
};
// 监听自定义事件
eventSource.addEventListener('update', (event) => {
console.log('自定义事件数据:', event.data);
});
// 错误处理
eventSource.onerror = (error) => {
console.error('SSE 错误:', error);
};
服务器实现(Node.js 示例)[编辑 | 编辑源代码]
使用 Express 框架返回 `text/event-stream` 响应:
const express = require('express');
const app = express();
app.get('/sse-endpoint', (req, res) => {
// 设置响应头
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// 每秒发送一次数据
let counter = 0;
const interval = setInterval(() => {
counter++;
// 发送未命名事件
res.write(`data: ${JSON.stringify({ time: new Date(), count: counter })}\n\n`);
// 发送自定义事件
if (counter % 3 === 0) {
res.write(`event: update\ndata: ${counter}\n\n`);
}
}, 1000);
// 客户端断开连接时清理
req.on('close', () => clearInterval(interval));
});
app.listen(3000);
输出示例[编辑 | 编辑源代码]
客户端控制台将显示:
收到数据: {"time":"2023-10-01T12:00:01.000Z","count":1} 收到数据: {"time":"2023-10-01T12:00:02.000Z","count":2} 自定义事件数据: 3
协议细节[编辑 | 编辑源代码]
事件流格式[编辑 | 编辑源代码]
每条消息由以下字段组成(字段间用 `\n` 分隔):
- data:有效载荷(可多行)
- event:自定义事件类型(可选)
- id:事件 ID(用于断线重连)
- retry:重连延迟(毫秒)
示例:
event: notification data: {"user": "Alice", "action": "login"} id: 42 retry: 5000
Mermaid 流程图[编辑 | 编辑源代码]
实际案例[编辑 | 编辑源代码]
实时日志监控[编辑 | 编辑源代码]
场景:开发者在控制台查看服务器日志流。
// 客户端
const logSource = new EventSource('/logs');
logSource.onmessage = (event) => {
document.getElementById('log-output').innerHTML += event.data + '<br>';
};
// 服务器(Node.js)
app.get('/logs', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
const logStream = fs.createReadStream('app.log');
logStream.on('data', (chunk) => res.write(`data: ${chunk}\n\n`));
});
数学公式支持[编辑 | 编辑源代码]
SSE 的带宽效率(假设无压缩)可表示为: 其中 为数据大小, 为协议头开销。
注意事项[编辑 | 编辑源代码]
- 跨域问题:需配置 CORS(如 `Access-Control-Allow-Origin`)
- 性能限制:单个浏览器最多允许 6 个 SSE 连接
- 协议选择:高频双向通信建议使用 WebSocket