Server-Sent Events 服務(wù)端發(fā)送事件
大多數(shù)時(shí)候,網(wǎng)頁必須向服務(wù)器發(fā)送請(qǐng)求以接收新數(shù)據(jù)。服務(wù)端發(fā)送的事件,可以將消息推送到網(wǎng)頁。
什么是SSE(Server-Sent Events)
本質(zhì)上,SSE使用戶可以訂閱實(shí)時(shí)數(shù)據(jù)流。
每當(dāng)此數(shù)據(jù)流更新時(shí),用戶都可以實(shí)時(shí)看到新事件。
如果你知道Long-Polling或Web Socket那么你可能覺得它沒什么大不了
SSE vs Web-Socket
Websocket是服務(wù)器之間的雙向通信形式。
它通常用于建立聊天室或多人視頻游戲,因?yàn)檫@些應(yīng)用程序場(chǎng)景需要服務(wù)器和客戶端之間的持續(xù)通信。
你可以將SSE視為單向websocket。只有服務(wù)器可以將消息發(fā)送到訂閱的客戶端。在許多Web應(yīng)用程序中,Web套接字可能會(huì)過大。
例如,商品的價(jià)格不需要雙向通信。服務(wù)器僅需要單向通信來更新其所有客戶端的價(jià)格。
但是在客戶端與服務(wù)端需要強(qiáng)交互的場(chǎng)景下,Web Socket仍是最佳選擇
SSE vs Long-Polling
長輪詢是一種通信方法,客戶端定期訪問服務(wù)器獲取新數(shù)據(jù)。
適用于需要經(jīng)過一定時(shí)間的計(jì)算或者人工干預(yù)的響應(yīng)
SSE通常用于快速生成事件的應(yīng)用程序中,即時(shí)更新。
長輪訓(xùn)雖然可以避免短輪訓(xùn)造成的服務(wù)端過載,但在服務(wù)端返回?cái)?shù)據(jù)后仍需要客戶端主動(dòng)發(fā)起下一個(gè)長輪訓(xùn)請(qǐng)求,等待服務(wù)端響應(yīng)
特性&限制
1.SSE是單向的 消息數(shù)據(jù)是從服務(wù)器到客戶端,單向傳遞 2.如果不使用HTTP/2會(huì)受到最大打開連接數(shù)的限制 瀏覽器對(duì)每個(gè)域名限制的http連接數(shù)為6,這是跨標(biāo)簽的。HTTP/2默認(rèn)值是100
客戶端接受消息
瀏覽器EventSource實(shí)例將創(chuàng)建一個(gè)持久的HTTP連接,直到通過調(diào)用關(guān)閉eventSource.close()。
const es = new EventSource('/v1/index/es')
es.onopen = () => {
console.log('es open')
}
es.onerror = (err) => {
console.log('err', err)
}
es.addEventListener('test', (res) => {
const { data } = res
console.log('來自服端消息:', data)
})
服務(wù)端發(fā)送消息
發(fā)送事件需要使用text/event-stream類型。每個(gè)消息均以文本塊形式發(fā)送,并以一對(duì)換行符結(jié)尾。
event 標(biāo)識(shí)所描述事件類型的字符串
如果指定了 在瀏覽器上將觸發(fā)指定的偵聽器
addEventListener()用于偵聽命名事件。
onmessage則處理未指定事件名稱的消息。
data 消息的數(shù)據(jù)字段
id 事件ID
retry 嘗試發(fā)送事件時(shí)要使用的重新連接時(shí)間 必須是整數(shù),以毫秒為單位
代碼 const { Readable } = require('stream')
// 寫入數(shù)據(jù)
const send = (stream, event, data) => {
return stream.push(`event:${event}\ndata: ${JSON.stringify(data)}\n\n`)
}
router.all('/es', async (ctx) => {
// 創(chuàng)建流
const reader = new Readable()
reader._read = function (data) {
console.log('>')
}
ctx.set({
'Content-Type': 'text/event-stream', // 響應(yīng)格式
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
})
send(reader, 'test', { data: 111 })
ctx.body = reader
let count = 1
// 模擬消息發(fā)送
const timer = setInterval(() => {
send(reader, 'test', { data: 111, count: count++ })
}, 3000)
// 處理連接斷開
ctx.req.on('close', () => {
console.log('close')
clearInterval(timer)
reader.destroy()
})
})
代碼倉庫
https://gitee.com/wjj0720/server-sent-events.git

評(píng)論
圖片
表情
