伺服器傳送事件(SSE) vs. WebSockets

banq發表於2022-02-18

在開發實時 Web 應用程式時,WebSockets可能是您首先想到的。但是,伺服器傳送事件 (SSE) 是一種更簡單的替代方案,通常更勝一籌。

 

WebSockets

WebSockets支援在瀏覽器和伺服器之間建立雙向 低延遲通訊通道。

這使得它們在某些場景中非常理想,例如多人遊戲,其中通訊是雙向的,因為瀏覽器和伺服器始終在通道上傳送訊息,並且要求這些訊息以低延遲傳遞.

在第一人稱射擊遊戲中,瀏覽器可以持續傳輸玩家的位置,同時從伺服器接收所有其他玩家位置的更新。此外,我們絕對希望以儘可能少的開銷傳遞這些訊息,以避免遊戲感覺遲緩。

這與傳統的HTTP[url=https://en.wikipedia.org/wiki/Request%E2%80%93response]請求-響應模型[/url]相反,其中瀏覽器始終是發起通訊的一方,並且由於建立TCP 連線HTTP 標頭,每條訊息都有很大的開銷。

但是,許多應用程式沒有這麼嚴格的要求。即使在實時應用程式中,資料流通常也是不對稱的:伺服器傳送大部分訊息,而客戶端主要只是偵聽,偶爾傳送一些更新。例如,在聊天應用程式中,使用者可能連線到許多房間,每個房間都有數十或數百名參與者。因此,收到的訊息量遠遠超過傳送的訊息量。

WebSocket 有什麼問題?

WebSockets 有一個主要缺點:它們不能在 HTTP 之上工作,至少不能完全工作。他們需要自己的 TCP 連線。他們僅使用 HTTP 來建立連線,然後將其升級為可以使用 WebSocket 協議的獨立 TCP 連線。

這似乎沒什麼大不了的,但這意味著WebSockets 不能從任何 HTTP 特性中受益。那是:

  • 不支援壓縮
  • 不支援 HTTP/2 多路複用
  • 代理的潛在問題
  • 無法防止跨站點劫持

至少,這是 WebSocket 協議剛釋出時的情況。如今,有一些補充標準試圖改善這種情況。讓我們仔細看看目前的情況。

 

伺服器傳送的事件SSE

伺服器傳送事件使伺服器能夠隨時向客戶端傳送低延遲推送事件。它們使用一個非常簡單的協議,該協議是HTML 標準的一部分,每個瀏覽器都支援

與 WebSocket 不同,伺服器傳送的事件只有一種方式流動:從伺服器到客戶端。這使得它們不適合一組非常特定的應用程式,即那些需要雙向和低延遲通訊通道的應用程式,例如實時遊戲。然而,這種權衡也是它們相對於 WebSockets 的主要優勢,因為作為單向,伺服器傳送事件在 HTTP 之上無縫工作,不需要自定義協議. 這使他們能夠自動訪問 HTTP 的所有功能,例如壓縮或 HTTP/2 多路複用,使其成為大多數實時應用程式的非常方便的選擇,在這些應用程式中,大部分資料是從伺服器傳送的,而由於 HTTP 標頭,請求中的少量開銷是可以接受的。

該協議非常簡單。它使用以下text/event-stream形式的 Content-Type 和訊息:

data: First message

event: join
data: Second message. It has two
data: lines, a custom event type and an id.
id: 5

: comment. Can be used as keep-alive

data: Third message. I do not have more data.
data: Please retry later.
retry: 10

每個事件由兩個空行 ( \n) 分隔,並由各種可選欄位組成。

  • data欄位可以重複以表示訊息中的多行,不出所料地用於事件的內容。
  • event欄位允許指定自定義事件型別,正如我們將在下一節中展示的,可用於在客戶端觸發不同的事件處理程式。
  • 其他兩個欄位id和retry用於配置自動重新連線機制的行為。這是伺服器傳送事件最有趣的功能之一。它確保 當連線被伺服器斷開或關閉時,客戶端將自動嘗試重新連線,而無需任何使用者干預。
  • retry欄位用於指定在嘗試重新連線之前等待的最短時間(以秒為單位)。它也可以由伺服器在關閉客戶端連線之前立即傳送,以在連線太多客戶端時減少其負載。
  • id欄位將識別符號與當前事件相關聯。重新連線時,客戶端將使用Last-Event-IDHTTP 標頭將上次看到的 id 傳輸到伺服器。這允許從正確的點恢復流。
  • 最後,伺服器可以通過返回HTTP 204 No Content響應來完全停止自動重新連線機制。

 

比較程式碼

在本節中,我們將使用 Server-Sent Events 和 WebSockets 實現一個簡單的服務。這應該使我們能夠比較這兩種技術。我們將瞭解開始使用每個功能是多麼容易,並手動驗證前幾節中討論的功能。

我們將使用 Python 作為後端,Caddy 作為反向代理,當然還有幾行 JavaScript 作為前端。

為了使我們的示例儘可能簡單,我們的後端將僅包含兩個端點,每個端點都流式傳輸一個唯一的隨機數序列。它們將可以從 伺服器傳送的事件以及從/sse1WebSockets訪問。雖然我們的前端將由一個 檔案組成,但有一些 JavaScript 可以讓我們啟動和停止 WebSockets 和伺服器傳送事件連線。/sse2/ws1/ws2index.html

此示例的程式碼可在 GitHub 上找到

更多點選標題

相關文章