HTTP Server-Sent Events - 服务器推送的简单实现方式
## 前言
在现代 Web 应用中,实时通信已成为许多功能的基础需求。无论是社交媒体的实时更新、聊天应用的消息推送,还是金融数据的实时展示,都需要服务器能够主动向客户端推送数据。
我们已经了解了 WebSocket 和 MQTT 这两种强大的实时通信协议,但它们在某些场景下可能显得过于复杂。今天,我将介绍一种更轻量级的服务器到客户端的实时通信技术——Server-Sent Events (SSE)。
::: tip
Server-Sent Events (SSE) 是一种允许服务器向客户端推送事件的 Web 技术。它是 HTML5 标准的一部分,基于 HTTP 协议实现,使用简单且兼容性好。
:::
## 什么是 Server-Sent Events?
Server-Sent Events (SSE) 是一种服务器向客户端推送数据的技术。与传统的客户端请求-服务器响应模式不同,SSE 允许服务器在数据更新时主动向客户端发送消息,而不需要客户端先发起请求。
SSE 基于 HTTP 协议实现,使用 `text/event-stream` MIME 类型。服务器通过保持一个长连接,定期发送数据事件,客户端则通过 `EventSource` API 接收这些事件。
## SSE 的特点
与 WebSocket 和 MQTT 相比,SSE 有以下特点:
### 优点
1. **简单易用**:SSE 基于 HTTP 协议,实现相对简单,不需要复杂的握手和协议协商。
2. **自动重连**:SSE 客户端内置了自动重连机制,在网络中断后会自动尝试重新连接。
3. **轻量级**:SSE 使用简单的文本格式传输数据,开销小,适合简单的服务器推送场景。
4. **标准支持**:SSE 是 HTML5 标准的一部分,所有现代浏览器都原生支持。
### 缺点
1. **单向通信**:SSE 只支持服务器到客户端的单向通信,客户端无法通过同一个连接向服务器发送数据。
2. **不支持二进制数据**:SSE 只支持文本数据,无法直接传输二进制数据(如图片、视频等)。
3. **并发连接限制**:浏览器对同一服务器的并发连接数有限制(通常为6个),这可能会影响需要多个 SSE 连接的应用。
## SSE 与 WebSocket 的比较
| 特性 | SSE | WebSocket |
|------|-----|----------|
| 协议 | 基于 HTTP | 独立的协议 |
| 数据格式 | 纯文本 | 文本和二进制 |
| 通信方向 | 单向(服务器→客户端) | 双向 |
| 自动重连 | 内置支持 | 需要手动实现 |
| 复杂度 | 简单 | 复杂 |
| 适用场景 | 简单的服务器推送 | 需要双向通信的复杂应用 |
## SSE 的基本使用
### 客户端实现
在客户端,我们可以使用 `EventSource` API 来接收 SSE 事件:
```javascript
// 创建 EventSource 对象
const eventSource = new EventSource('/api/events');
// 监听消息事件
eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log('收到消息:', data);
};
// 监听特定类型的事件
eventSource.addEventListener('custom-event', function(event) {
const data = JSON.parse(event.data);
console.log('收到自定义事件:', data);
});
// 监听错误事件
eventSource.onerror = function(error) {
console.error('SSE 错误:', error);
// 如果连接断开,EventSource 会自动尝试重连
// 我们也可以手动关闭连接
// eventSource.close();
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# 服务器实现
在服务器端,我们需要设置正确的 HTTP 头并持续发送事件数据。以下是一个 Node.js 的示例:
const http = require('http');
const server = http.createServer((req, res) => {
// 只处理 /api/events 路径的请求
if (req.url === '/api/events') {
// 设置 SSE 所需的 HTTP 头
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*' // 允许跨域
});
// 发送一条初始消息
res.write('data: {"type": "connection", "message": "连接成功"}\n\n');
// 模拟定期发送数据
const intervalId = setInterval(() => {
const data = {
type: 'update',
message: `当前时间: ${new Date().toLocaleString()}`,
value: Math.random()
};
res.write(`data: ${JSON.stringify(data)}\n\n`);
}, 1000);
// 当客户端断开连接时,清除定时器
req.on('close', () => {
clearInterval(intervalId);
console.log('客户端断开连接');
});
} else {
res.writeHead(404);
res.end('Not Found');
}
});
server.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# SSE 的数据格式
SSE 使用简单的文本格式传输数据。每条消息由一个或多个字段组成,字段之间用换行符分隔,消息之间用双换行符(\n\n)分隔。
# 基本字段
- data:消息的内容。可以有多行 data 字段,它们会被视为同一个消息的一部分。
- event:事件的类型。客户端可以通过
addEventListener监听特定类型的事件。 - id:事件的唯一标识符。用于断线重连时从上次的位置继续接收数据。
- retry:客户端重连的延迟时间(毫秒)。
# 示例
data: {"type": "message", "content": "这是一条消息"}
event: notification
data: {"type": "notification", "content": "这是一条通知"}
id: 12345
retry: 5000
data: {"type": "heartbeat", "content": "心跳"}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# SSE 的进阶使用
# 自定义事件类型
除了默认的 message 事件外,我们还可以发送自定义事件类型:
// 服务器端
res.write('event: customEvent\ndata: {"message": "这是一个自定义事件"}\n\n');
// 客户端
eventSource.addEventListener('customEvent', function(event) {
console.log('收到自定义事件:', event.data);
});
1
2
3
4
5
6
7
2
3
4
5
6
7
# 事件 ID 和重连
SSE 支持事件 ID,用于断线重连时从上次的位置继续接收数据:
// 服务器端
let eventId = 0;
setInterval(() => {
eventId++;
res.write(`id: ${eventId}\ndata: {"message": "消息 #${eventId}"}\n\n`);
}, 1000);
// 客户端
eventSource.onmessage = function(event) {
console.log('最后接收到的 ID:', event.lastEventId);
};
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# SSE 的应用场景
SSE 适用于以下场景:
- 实时通知:如社交媒体更新、新闻推送、邮件通知等。
- 实时数据展示:如股票价格、体育赛事比分、天气预报等。
- 日志监控:实时显示服务器日志或应用程序日志。
- 聊天应用:简单的服务器到客户端的消息推送(如果需要双向通信,可以考虑结合 WebSocket)。
# SSE 的浏览器兼容性
SSE 得到了所有现代浏览器的支持:
- Chrome
- Firefox
- Safari
- Edge
需要注意的是,Internet Explorer 不支持 SSE。
# 结语
Server-Sent Events 是一种简单而有效的服务器到客户端的实时通信技术。它基于 HTTP 协议,实现简单,兼容性好,特别适合不需要双向通信的实时推送场景。
与 WebSocket 相比,SSE 更轻量级,实现更简单;与 MQTT 相比,SSE 更适合 Web 应用,不需要额外的客户端库。
在选择实时通信技术时,应根据具体需求和技术栈来决定:
- 如果只需要服务器到客户端的单向通信,且希望实现简单,SSE 是一个不错的选择。
- 如果需要双向通信,或者需要支持移动应用和物联网设备,WebSocket 可能更合适。
- 如果是在物联网环境中,需要低带宽、低功耗的通信,MQTT 可能是更好的选择。
希望这篇文章能帮助你了解 SSE 并在项目中应用它。如果你有任何问题或建议,欢迎在评论区留言交流!
"简单是复杂的终极形式。" —— 达·芬奇
上次更新: 2026/01/28, 14:21:05