Server-Sent Events(SSE)是一种服务器向客户端推送实时更新的技术,基于HTTP协议。客户端通过EventSource API来接收事件流,而服务器则保持一个长连接,持续发送数据。这与传统的请求-响应模式不同,允许服务器主动推送数据,而不是等待客户端请求。
客户端通过创建一个EventSource对象,指定服务器的URL。服务器设置特定的HTTP头(如Content-Type: text/event-stream)并保持连接打开。服务器可以周期性或根据事件发送数据,数据格式遵循SSE的规范,每条消息以"data: "开头,后跟数据内容,用两个换行结束。
然后,优缺点分析。优点是简单易用,基于HTTP,兼容性好,适合低频更新。缺点是单向通信,服务器到客户端,不支持客户端发送数据;同时,HTTP协议本身不是为长连接设计的,可能在某些情况下效率不如WebSocket。
适用场景包括实时新闻推送、股票行情更新、日志监控等不需要高频双向通信的场景。而如果应用需要高频通信或双向通信,WebSocket可能更合适。
最后,可能需要提到一些实现细节,比如数据格式、事件类型、重试机制等,以及如何在不同后端语言中实现SSE,比如java、PHP、Node.js等。
1. 工作原理
- 客户端:通过 JavaScript 的 EventSource API 建立长连接
- 服务端:设置 Content-Type: text/event-stream 响应头,保持连接持续打开
- 通信方式:服务器按需发送文本数据流(UTF-8 编码),客户端自动解析
2. 核心优势
- 轻量级:基于 HTTP 协议,无需复杂握手
- 自动重连:内置断线重试机制
- 兼容性佳:所有现代浏览器均支持
- 简单实现:服务端只需保持长连接并发送文本流
3. 典型应用场景
- 实时数据看板(如股票行情、系统监控)
- 日志流实时查看
- 通知推送系统
- 协作工具中的实时更新
4. 与 WebSocket 对比
特性 | SSE | WebSocket |
---|---|---|
通信方向 | 单向(服务器→客户端) | 双向 |
协议 | HTTP | 独立协议 |
连接数 | 天然支持多标签页共享 | 需自行处理多连接 |
数据格式 | 文本流 | 二进制/文本 |
适用场景 | 低频更新 | 高频/双向通信 |
5. 最佳实践建议
- 频率控制:建议至少间隔 1 秒发送数据,避免高频触发重绘
- 数据压缩:使用 gzip 或 deflate 压缩传输内容
- 错误处理:监听 onerror 事件并实现自动重连逻辑
- 性能优化:结合 Last-Event-ID 实现断点续传
- 安全退出:结束时发送空消息或特殊标识(如 data: END)
6. 代码示例
服务端源码
const express = require('express');
const app = express();
const port = 3000;
// 静态文件服务
app.use(express.static('public'));
// SSE路由
app.get('/events', (req, res) => {
// 设置SSE所需的头信息
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// 发送初始消息
res.write('data: Connected to SSE server\n\n');
// 定时发送消息
let counter = 0;
const intervalId = setInterval(() => {
counter++;
const data = {
message: `Server time: ${new Date().toISOString()}`,
counter: counter
};
res.write(`data: ${JSON.stringify(data)}\n\n`);
// 模拟结束条件
if (counter >= 10) {
res.write('event: end\ndata: Stream ended\n\n');
clearInterval(intervalId);
res.end();
}
}, 1000);
// 客户端断开连接时清理
req.on('close', () => {
console.log('Client disconnected');
clearInterval(intervalId);
res.end();
});
});
app.listen(port, () => {
console.log(`SSE server running at http://localhost:${port}`);
});
客户端H5页面端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSE Demo</title>
</head>
<body>
<h1>Server-Sent Events Demo</h1>
<div id="events"></div>
<script>
const eventSource = new EventSource('/events');
const eventsDiv = document.getElementById('events');
// 监听默认消息事件
eventSource.onmessage = function(e) {
const data = JSON.parse(e.data);
const p = document.createElement('p');
p.textContent = `${data.message} (Count: ${data.counter})`;
eventsDiv.appendChild(p);
};
// 监听自定义事件
eventSource.addEventListener('end', function(e) {
const p = document.createElement('p');
p.textContent = `Event: ${e.type}, Data: ${e.data}`;
eventsDiv.appendChild(p);
eventSource.close();
console.log('EventSource closed');
});
// 错误处理
eventSource.onerror = function(e) {
console.error('EventSource failed:', e);
eventSource.close();
};
</script>
</body>
</html>
7. 注意事项
连接管理:确保在客户端断开连接时清理定时器和资源
重连机制:SSE客户端会自动尝试重新连接
CORS:如果客户端和服务器不同源,需要设置CORS头
性能考虑:对于大量客户端连接,考虑使用专门的解决方案如Redis PUB/SUB
浏览器支持:大多数现代浏览器都支持SSE,但不包括IE
SSE 适用于大多数实时性要求不高的场景,如实时通知、股票行情、新闻推送等。其简洁性和兼容性使其成为轻量级实时通信的首选方案。对于需要双向通信或高频更新的场景,建议考虑 WebSocket 技术。