1. 什么是 SSE?
Server-Sent Events (SSE) 是一种允许服务器向客户端推送数据的 Web 技术:
- 它建立在 HTTP 协议之上,是一种单向通信机制(服务器→客户端)
- 使用持久化的 HTTP 连接实现实时数据推送
- 数据格式为 UTF-8 编码的文本消息
- 浏览器原生支持,使用 EventSource API
2. SSE vs 其他实时通信技术
2.1 Client Polling
- 客户端定期轮询服务器
- 实现简单但效率低
- 即使没有更新也会发送请求
2.2 WebSocket
- 双向通信
- 需要额外的协议支持
- 实现相对复杂
2.3 SSE的优势
- 基于 HTTP,实现简单
- 自动重连机制
- 原生事件 ID 跟踪
- 标准化的消息格式
3. 适用场景
SSE 特别适合以下应用场景:
- 实时股票行情
- 体育比分直播
- 新闻推送
- 系统通知
- 物联网数据推送
- 电商实时信息
- 监控系统
4. 技术实现
4.1 服务器端实现
服务器需要:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
消息格式:
id: <事件ID>
event: <事件类型>
data: <事件数据>
retry: <重连时间>
4.2 客户端实现
const eventSource = new EventSource('http://localhost:3000/events');
// 处理连接打开
eventSource.onopen = (event) => {
console.log('Connection opened');
};
// 处理消息
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Received:', data);
};
// 处理错误
eventSource.onerror = (error) => {
console.error('EventSource failed:', error);
eventSource.close();
};
// 监听自定义事件
eventSource.addEventListener('customEvent', (event) => {
console.log('Custom event:', event.data);
});
4.3 Node.js SSE 实现示例
// 创建Express应用实例
const app = express();
// SSE(服务器发送事件)端点
app.get('/events', (req, res) => {
// 设置SSE所需的HTTP头
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// 每2秒发送一条普通消息
const timeIntervalId = setInterval(() => {
const data = {
time: new Date().toLocaleTimeString(),
message: 'Server time update'
};
res.write(`data: ${JSON.stringify(data)}\n\n`);
}, 2000);
// 每5秒发送一条自定义事件消息
const customIntervalId = setInterval(() => {
const customData = {
time: new Date().toLocaleTimeString(),
message: 'This is a custom event!'
};
// 发送带有自定义事件类型的SSE数据
res.write(`event: customEvent\n`);
res.write(`data: ${JSON.stringify(customData)}\n\n`);
}, 5000);
// 当客户端断开连接时清理所有定时器
req.on('close', () => {
clearInterval(timeIntervalId);
clearInterval(customIntervalId);
});
});
5. 注意事项与限制
5.1 主要限制
- 仅支持文本数据(UTF-8),不支持二进制,消息格式必须符合 SSE 规范(如结尾需要
\n\n) - 浏览器对同一域名有 TCP 连接数限制(通常为 6-8 个),HTTP1.1每个 SSE 连接会占用一个 TCP 连接,当达到最大连接数时,新的 SSE 连接将被阻塞或失败。可以使用HTTP2.0支持多路复用,单个 TCP 连接可处理多个 SSE 流
- IE不支持SSE,需要考虑降级方案(如 long polling),主流现代浏览器(Chrome、Firefox、Safari、Edge)都支持
5.2 最佳实践
- 实现错误处理和重试机制
- 合理设置超时和重连间隔
- 考虑服务器负载能力
- 在需要时正确关闭连接
参考资料
根据搜索结果,我来为您总结一份关于Server-Sent Events (SSE)的详细教程:
1. 什么是 SSE?
Server-Sent Events (SSE) 是一种允许服务器向客户端推送数据的 Web 技术:
- 它建立在 HTTP 协议之上,是一种单向通信机制(服务器→客户端)
- 使用持久化的 HTTP 连接实现实时数据推送
- 数据格式为 UTF-8 编码的文本消息
- 浏览器原生支持,使用 EventSource API
2. SSE vs 其他实时通信技术
2.1 Client Polling
- 客户端定期轮询服务器
- 实现简单但效率低
- 即使没有更新也会发送请求
2.2 WebSocket
- 双向通信
- 需要额外的协议支持
- 实现相对复杂
2.3 SSE的优势
- 基于 HTTP,实现简单
- 自动重连机制
- 原生事件 ID 跟踪
- 标准化的消息格式
3. 适用场景
SSE 特别适合以下应用场景:
- 实时股票行情
- 体育比分直播
- 新闻推送
- 系统通知
- 物联网数据推送
- 电商实时信息
- 监控系统
4. 技术实现
4.1 服务器端实现
服务器需要:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
消息格式:
id: <事件ID>
event: <事件类型>
data: <事件数据>
retry: <重连时间>
4.2 客户端实现
基本用法:
const evtSource = new EventSource("/api/events");
evtSource.onmessage = (event) => {
console.log(event.data);
};
// 监听特定事件
evtSource.addEventListener("custom-event", (e) => {
console.log(e.data);
});
4.3 Spring WebFlux 实现示例
@GetMapping(path = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> streamEvents() {
return Flux.interval(Duration.ofSeconds(1))
.map(sequence -> ServerSentEvent.<String>builder()
.id(String.valueOf(sequence))
.event("periodic-event")
.data("SSE - " + LocalTime.now().toString())
.build());
}
5. 注意事项与限制
5.1 主要限制
- 仅支持文本数据(UTF-8),不支持二进制
- 默认每个浏览器限制6个并发SSE连接
- IE不支持SSE
5.2 最佳实践
- 实现错误处理和重试机制
- 合理设置超时和重连间隔
- 考虑服务器负载能力
- 在需要时正确关闭连接
6. 调试与测试
- 使用浏览器开发者工具监控SSE连接
- 测试断线重连机制
- 验证消息格式正确性
- 压力测试并发连接数
参考资料
QA
Q:什么是服务器发送事件(SSE)?它的核心特点是什么?
A:SSE 是一种允许服务器向浏览器推送实时更新的技术。核心特点包括单向通信、基于 HTTP 协议、自动重连和事件流格式。
Q:SSE 与 WebSocket 有什么区别?请列出至少三个主要区别。
A:
1️⃣ SSE 是单向通信,WebSocket 是双向通信。
2️⃣ SSE 使用 HTTP 协议,WebSocket 使用 ws/wss 协议。
3️⃣ SSE 更适合简单的服务器推送,WebSocket 更适合复杂的实时交互。
4️⃣ SSE 只支持文本,WebSocket 支持文本和二进制
5️⃣ SSE 原生支持自动重连,WebSocket 需要手动实现
Q:使用 SSE 通信的优点和局限性分别是什么?
A:**优点:**简单易用、自动重连、支持事件流。**局限性:**仅支持单向通信、受限于 HTTP 连接数、可能被代理拦截。
Q:如何在前端实现 SSE?请用代码展示如何订阅 SSE 消息。
A:
const eventSource = new EventSource('your-server-url');
eventSource.onmessage = function(event) {
console.log('Message:', event.data);
};
Q:SSE 的 Content-Type 为什么必须是 text/event-stream?
A:这是 SSE 规范要求,text/event-stream 是 SSE 专用的 MIME 类型,它告知浏览器这是一个事件流,
Q:在后端如何实现 SSE?请用任意后端语言描述实现过程(如 Node.js、Python)。
A:笔记中有代码
Q:SSE 是单向通信还是双向通信?如何结合其他技术实现双向通信?
A:SSE 是单向通信,浏览器从服务器接收数据,而客户端不能直接通过同一连接发送数据回服务器。如果需要双向通信,可以结合 WebSocket 技术来实现
Q:如何处理 SSE 连接的自动重连?浏览器的默认重连策略是什么?
A:**浏览器有内建的重连机制:**如果 SSE 连接丢失,它会自动重新连接,默认的重连时间是 3秒。服务端也可以通过 retry 字段来指定自定义的重连时间(单位是毫秒)。例如:
res.write('retry: 5000\n'); // 设置重连时间为 5 秒
**客户端自动重连流程:**如果需要自定义重连机制,客户端可以监听 onerror 事件,并手动重新创建 EventSource 实例:
const eventSource = new EventSource('/events');
eventSource.onerror = function () {
console.error('Connection lost, reconnecting...');
eventSource.close(); // 关闭旧连接
const newEventSource = new EventSource('/events'); // 创建新连接
};
Q:如果有多个 SSE 客户端连接到服务器,如何管理这些连接?
A:服务端可以维护一个连接列表,并循环给每个连接推送数据。这是通过将每个客户端连接的 res 对象存储在一个数组或对象中来实现的:
let clients = [];
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// 将当前连接保存到客户端列表中
clients.push(res);
// 每隔1秒广播消息给所有客户端
const intervalId = setInterval(() => {
const message = { text: 'Broadcast message', timestamp: new Date() };
clients.forEach(client => client.write(`data: ${JSON.stringify(message)}\n\n`));
}, 1000);
// 客户端断开时清除其连接
req.on('close', () => {
clients = clients.filter(client => client !== res);
clearInterval(intervalId);
});
});
Q:SSE 的事件流数据格式有什么要求?如果想自定义事件类型,应该如何处理?
每条消息以 data: 开头,后面跟随实际的消息内容。每条消息以两个换行符(\n\n)结束。如果要使用自定义事件类型,可以使用 event: 字段指定:
res.write('event: customEvent\n');
res.write('data: {"message": "Hello, custom event"}\n\n');