SSE(Server-Sent Events 服务器推送事件)

545 字
3 分钟
SSE(Server-Sent Events 服务器推送事件)

SSE(Server-Sent Events 服务器推送事件),是一种特殊的 HTTP 请求,在浏览器建立连接后,服务器可以分批次、有间隔的向浏览器下发数据,它常常拿来与 websocket 做比较

SSEwebsocket
单向连接双向连接
HTTP 协议TCP 协议
内置断线重连-
UTF-8 文本数据流消息类型广泛

概念#

浏览器使用EventSource建立连接

const evtSource = new EventSource('//xxx/xx', { withCredentials: true })

服务器使用 text/event-stream MIME 类型响应内容

res.writeHead(200, {
'Content-Type': 'text/event-stream',
Connection: 'keep-alive',
'Cache-Control': 'no-cache',
'Access-Control-Allow-Origin': '*', // 允许跨域
})

响应内容是一个 UTF-8 的文本数据流,由:分隔字段名与值,由 \n\n 分隔消息。 以:开头的行为注释行,会被忽略。 合法字段名只有:event 事件名、data 数据、id、retry 毫秒。

res.write(`event: testEvent\n`)
res.write(`id: 123\n`)
res.write(`retry: 30000\n`)
res.write(`data: {"a":4}\n\n`)

浏览器使用 onmessage 和 addEventListener 监听服务器消息,没有指定 event 会触发前者,否则触发后者

evtSource.onmessage = function (event) {
console.log('收到无 event 字段消息', event)
}
evtSource.addEventListener('testEvent', (event) => {
console.log('收到指定 event 事件', event)
})

连接应由浏览器关闭,因为 EventSource 自带断线重连

evtSource.onerror = (err) => {
console.error('EventSource failed:', err)
}
evtSource.close()
req.on('close', () => {
res.end()
})

demo#

官方推荐使用EventSource类创建 sse 连接,但它只能建立 get 请求,且无法自定义 header

npm 上现在已经有不少相关包了,基于 Fetch、XMLHttpRequest 模拟了 EventSource 的 API,并支持了自定义 header 等功能,比如sse.js

// NODE
const http = require('http')
http
.createServer((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Access-Control-Allow-Origin': '*', // 允许跨域
})
// 连接由浏览器关闭
req.on('close', () => {
res.end()
})
setTimeout(() => sendTestEvent(res), 1000)
setTimeout(() => sendSimpleEvent(res), 2000)
})
.listen(3000)
function sendTestEvent(res) {
res.write(`event: testEvent\n`)
res.write(`id: 123\n`)
res.write(`retry: 30000\n`)
res.write(`data: {"a":4}\n\n`)
}
function sendSimpleEvent(res) {
res.write(`data: this is SimpleEvent\n\n`)
}
<script
type="module"
src="https://cdn.jsdelivr.net/npm/sse.js@2.4.1/lib/sse.js"
></script>
<script>
var evtSource = new SSE('http://localhost:3000')
evtSource.addEventListener('testEvent', (event) => {
console.log('收到指定 event 事件', event.data)
// => 收到指定 event 事件 {"a":4}
})
evtSource.onmessage = function (event) {
console.log('收到无 event 字段消息', event.data)
// => 收到无 event 字段消息 this is SimpleEvent
evtSource.close()
}
</script>

缺点/需要注意的点#

  • 因为 HTTP1.1 并发连接数是 6 个,打开多个标签页时会很麻烦
  • 兼容性:ie 不支持,edge 20 年开始支持,其它都支持的不错
SSE(Server-Sent Events 服务器推送事件)
https://wangxiang.website/posts/工作/sse/
作者
翔子
发布于
2024-04-29
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
翔子
前端开发工程师
公告
博客已从 VitePress 迁移到 Astro + Firefly 主题,223 篇文章全部保留。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
221
分类
9
标签
28
总字数
411,914
运行时长
0
最后活动
0 天前

文章目录