# 背景
服务端向客户端(浏览器)消息推送常用的两种方式:
- WebSocket 长链接
- http 轮询
轮询
由客户端主动发起,那有没有一种服务端主动发起的呢?
html5 SSE
即 Server-Send Events
满足了这样的需要
优点:
- 断线重连
- 自定义消息类型
- 重复
http
协议,现有接口代码少量改动即可使用 - 兼容性还不错,除了
IE
,大胆用~
缺点:
- 规定的传送数据字段只能为
data
且只可以传送文本
# 客户端(浏览器)实现
// 创建 sse 消息推送对象,监听服务端 sse 接口服务
const sse = new EventSource('http://127.0.0.1:8866/api/stream?q=sse')
// 打开连接
sse.addEventListener('open', (event) => {
console.log('open')
}, false)
// 监听服务端默认 message 事件信息
sse.addEventListener('message', event => {
console.log(event)
console.log(event.data)
})
// 监听服务端 sse 事件信息
sse.addEventListener('sse', event => {
console.log(event)
})
// 连接报错
sse.addEventListener('error', event => {
console.log(event)
})
// 5s 后断开连接
setTimeout(() => {
sse.close()
// 释放 open、message、see、error 事件
}, 5 * 1000)
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
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
# 服务器实现 (Nodejs)
// 主要代码逻辑
app.get('/api/stream', async (req, res) => {
let timer = null
// 消息块
// 消息块用 \n\n 结尾 不加?data 消息连接另外一条消息
// 消息块中单个字段用 \n 结尾 不加?此消息失效
// \n 前最好不要加空格,保证输出结果中没有空格
// event-stream 文本书写格式
if (!req.query.q) {
res.send('404')
return false
}
res.write(`retry: 1000\n`)
res.write(`id: ${+ new Date()}\n`)
res.write(`data: ${JSON.stringify({
eventName: 'message'
})}\n\n`)
timer = setInterval(() => {
// 另外消息块
// 自定义 sse 事件
res.write(`retry: 1000\n`)
res.write(`event: sse\n`)
res.write(`id: ${+ new Date()}\n`)
res.write(`data: ${JSON.stringify({
eventName: 'sse'
})}\n\n`)
}, 1000)
req.connection.addListener('close', () => {
console.log('SSE 关闭: closed')
clearInterval(timer)
timer = null
})
})
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
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
扫一扫,微信中打开