为了能使 SSE
正常工作,Server
端也需要作一些对应设置。
本节中 server
端相关代码,以 express
框架作为示范。
js
app.get('/api/sse', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream')
res.setHeader('Cache-Control', 'no-cache')
res.setHeader('Connection', 'keep-alive')
const startTime = Date.now()
const timer = setInterval(() => {
if (Date.now() - startTime >= 3000) {
clearInterval(timer)
// 测试发现 id字段不在data字段后 也起作用
res.write('event:foo\nid:foo\nretry: 10000\ndata:{ message: \'foo\' }\n\n')
const data = { message: 'close', timestamp: new Date() }
res.write(`data:${JSON.stringify(data)}\n\n`)
// res.end() 不会关闭SSE连接 但会触发error事件监听
res.end()
return
}
const data = { message: 'HelloWorld', timestamp: new Date() }
res.write(`data:${JSON.stringify(data)}\n\n`)
}, 1000)
})
1.响应头配置
SSE
的响应头配置是固定的,有以下三条:
js
// 定义响应数据为事件流类型
res.setHeader('Content-Type', 'text/event-stream')
// 定义客户端不进行清缓存 保证每次请求结果都是更新的
res.setHeader('Cache-Control', 'no-cache')
// 定义长连接 客户端EventSource会发送Connection请求头 此处作对应设置以保证长连接
res.setHeader('Connection', 'keep-alive')
TIP
测试发现,Connection
设置为 keep-alive
,该项非必需。
因为目前大部分后端程序会设置该项为默认值:
Connection: keep-alive
keep-alive: timeout=5
2.响应体格式
SSE
的一次的响应体推送,我们称作一个 message
。
message
的数据格式是字符串文本。
该 message
由 [field]: value
键值对格式的字符串拼接起来:
- 每个键值对之间需要使用
\n
分割开来; - 每个
message
末尾以\n\n
结尾。
field
只支持如下 4
个固定字段:
event
data
id
retry
单个 message
的格式可能如下:
js
// 1
`event:foo\nid:foo\nretry: 10000\ndata:{ message: 'foo' }\n\n`
// 2
`event:bar\ndata:{ message: 'bar' }\n\n`
2-1.event
event
字段用以自定义事件。
客户端可使用 addEventListener
作对应监听。
如果没有声明 event
字段,则默认触发 message
事件。
js
// server
res.write(`event:foo\nid:foo\nretry: 10000\ndata:{ message: 'foo' }\n\n`)
// client
source.addEventListener('foo', (event) => {
console.log(event.data)
})
2-2.data
data
字段用以设置事件数据。
客户端可使用 event.data
属性进行接收。
2-3.id
id
字段用以标识会话 ID
。主要用以 SSE
重连。
当设置了 id
字段后,如果 SSE
网络连接中断,那么在恢复重连后,会自动在请求头中设置 Last-Event-Id
字段。
该 Last-Event-Id
字段值与 id
字段值相对应。
TIP
恢复重连,是客户端自动进行的。
如果没有显示的使用 source.close()
方法进行关闭 SSE
连接,则每一次中断过后,经过一段时间,客户端都会自动重连。
2-4.retry
在上一节 id
字段的相关介绍中,我们提到了中断一定时间后,客户端都会自动重连。
而 retry
字段的功能就是用以设置中断时间具体时长。
retry
是有默认值的,笔者没有找到文档,根据实际代码推测是 3000ms
左右。
可以用如下代码设置覆盖:
js
res.write(`retry: 10000\ndata:{ message: 'Hello' }\n\n`)