本文同步發(fā)表在豆米的博客:豆米的博客
前言
前兩篇文章分析了websocket和socket.io,現(xiàn)在就剩下最后一個實時通信技術-eventsource。很多人也許好奇,有了websocket這種實時通信,為什么還需要eventsource呢?答案其實很簡單,那就是eventsource其實是單向通信,而websocket是雙向通信。在股票行情、新聞推送的這種只需要服務器發(fā)送消息給客戶端場景中,使用SSE更加合適。另外SSE是使用HTTP傳輸?shù)?這意味著我們不需要一個特殊的協(xié)議或者額外的實現(xiàn)就可以使用。而websocket要求全雙工連接和一個新的websocket服務器去處理。加上SSE在設計的時候就有一些websocket沒有的特性,比如自動重連接,event IDs,以及發(fā)送隨機事件的能力,所以各有各的特長,我們需要根據(jù)實際應用場景,去選擇不同的應用方案。
1、SSE介紹
SSE的簡單模型是:一個客戶端去從服務器端訂閱一條“流”,之后服務端可以發(fā)送消息給客戶端直到服務端或者客戶端關閉該“流”,所以eventsource也叫作"server-sent-event"。相比以前的輪詢,SSE可以為B2C帶來更高的效率。有一張圖片畫出了二者的區(qū)別:(引用自What is Server-Sent Events)

1.1、SSE數(shù)據(jù)幀的格式
event-source必須編碼成utf-8的格式,消息的每個字段使用"\n"來做分割,并且需要下面4個規(guī)范定義好的字段:
- Event: 事件類型
- Data: 發(fā)送的數(shù)據(jù)
- ID: 每一條事件流的ID
- Retry: 告知瀏覽器在所有的連接丟失之后重新開啟新的連接等待的時間,在自動重新連接的過程中,之前收到的最后一個事件流ID會被發(fā)送到服務端。
下圖是通過wireshark抓包得到的數(shù)據(jù)包的原始格式:
1.2、SSE通信過程
SSE的通信過程比較簡單,底層的一些實現(xiàn)都被瀏覽器給封裝好了,包括數(shù)據(jù)的處理。大致流程如下:
在瀏覽器中截圖如下:
攜帶的數(shù)據(jù)是JSON格式的,瀏覽器都幫你整合成為一個Object:
在wireshark中,其通信流程如下:
1.2.1、 發(fā)送請求
1.2.2、 得到響應
1.2.3、 在開始推送信息流之前,服務器還會發(fā)送一個客戶端會忽略掉的包,這個具體原因不清楚:
1.2.4、 斷開連接后的重傳
2、SSE的簡單使用示例
瀏覽器端的使用:
const es = new EventSource('/sse')
服務端的使用:
const sseStream = new SseStream(req)
sseStream.pipe(res)
sseStream.write({
id: sendCount,
event: 'server-time',
retry: 20000, // 告訴客戶端,如果斷開連接后,20秒后再重試連接
data: {ts: new Date().toTimeString(), count: sendCount++}
})
更多API使用和demo介紹分別參考:
3、兼容性以及缺點
3.1、兼容性

3.2、缺點
- 因為是服務器->客戶端的,所以它不能處理客戶端請求流
- 因為是明確指定用于傳輸UTF-8數(shù)據(jù)的,所以對于傳輸二進制流是低效率的,即使你轉為base64的話,反而增加帶寬的負載,得不償失。
4、結語
至此3篇關于RTC通信的文章介紹完成,但愿能夠給童鞋們一個基本的印象,在實際應用中如果有什么問題,歡迎探討。
參考
1、https://hpbn.co/server-sent-events-sse/
2、https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events
3、https://gist.github.com/jareware/aae9748a1873ef8a91e5
4、https://streamdata.io/blog/server-sent-events/