服务器发送事件(Server-Sent Events,简称 SSE) 其实就是浏览器向服务器发送一个 HTTP
请求,然后服务器不断单向地向浏览器推送消息
所谓的消息,其实就是一定格式的文本事件流(数据流)
SSE的特点
-
基于
http
协议的单向通信 -
默认支持断线重连,并支持发送自定义事件类型消息
-
只支持发送文本
-
是
WebSocket
的一种轻型替代方案,受同源策略的限制
消息的构成
-
消息唯一标识(id)
相当于每一条数据的编号,可通过
lastEventId
属性读取。一旦连接中断,浏览器会发送包含Last-Event-ID: id
头信息来帮助服务器重建连接 -
消息内容(data)
只能为文本字符串,发送
JSON
数据data:${JSON.stringify({ name: 'adiu', alias: '老夫子' })}\n\n
-
自定义事件类型(event)
服务器端可自定义,浏览器端通过
addEventListener
监听,如果未指定,则触发浏览器端的message
事件 -
最大间隔时间/毫秒(retry)
如果未指定通信的最大间隔时间,服务器端
3
秒内没有发送任何信息,浏览器端默认开始重连由于网络错误导致连接出错,浏览器也会自动重新发起连接
客户端代码
-
检测浏览器是否支持
if (!!window.EventSource) { console.log('当前浏览器支持事件推送') }
-
建立连接
if (!!window.EventSource) { const ets = new EventSource('http://127.0.0.1/sse/notice') }
-
连接状态(ets.readyState)
0
表示连接还未建立,或者连接断线1
表示连接已经建立,可以接受数据2
表示连接已断,且不会重连 -
建立连接,触发事件
ets.addEventListener('open', event => { console.log('handle open event') })
连接一旦建立,就会触发
open
事件 -
错误处理
ets.addEventListener('error', event => { console.log('handle error event') })
如果发生通信错误(比如连接中断),就会触发
error
事件 -
自定义事件
ets.addEventListener('notice', event => { const { data, origin, lastEventId } = event console.log('消息内容', data) console.log('服务器端URL的域名部分,即协议、域名和端口', origin) console.log('数据的编号,由服务器端发送。如果没有编号,这个属性为空', lastEventId) })
-
关闭推送
ets.close()
默认情况下,如果客户端和服务端之间的连接关闭,则会自动重连。可以通过
close()
方法终止连接
服务端代码
-
代码示例(nodejs)
router .prefix('/sse') .get('/notice', ctx => { ctx.set({ 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }) ctx.body = `event: notice\nretry: 5000\ndata: ${JSON.stringify({ name: 'adiu', alias: '老夫子' })}\n\n` })
-
无推送数据时的空闲时间处理
: This is a idle stream\n\n
以冒号开头的行,表示注释
通常,服务器每隔一段时间就会向浏览器发送一个注释,来保持连接不中断
注意事项
-
由于传输的数据格式必须是文本,所以每个字段之间要用换行符
\n
隔开,最后一个字段要用\n\n
表示一条消息的结束 -
服务端发送数据时必须设置响应头标识推送的数据是流信息
Content-Type: text/event-stream
-
不建议缓存事件推送数据
-
如果用户量很多,就需要保持很多长连接,因此会占用服务器大量内存和连接数
一起学习,加群交流看 沸点