首頁 >web前端 >js教程 >服務器範圍事件

服務器範圍事件

尊渡假赌尊渡假赌尊渡假赌
尊渡假赌尊渡假赌尊渡假赌原創
2025-02-27 09:25:10870瀏覽

Server-sent Events

核心要點

  • 服務器發送事件 (SSE) 是一種利用流將數據和/或 DOM 事件從服務器推送到客戶端的方法,非常適用於需要定期更新數據的情況,例如體育比分或股票行情。
  • 創建 EventSource 對象允許您訂閱事件流,並能夠處理打開、消息和錯誤事件。
  • 從服務器發送事件需要使用 Content-type 頭部(值為 text/event-stream)和 UTF-8 字符編碼來提供內容。服務器發送事件的語法包括數據、事件類型、事件標識符和重試間隔。
  • 事件處理可以使用 onmessage 函數(僅用於發送消息事件的應用程序),但 addEventListener 方法對於處理自定義事件更靈活。
  • 大多數現代瀏覽器(包括 Chrome、Firefox 和 Safari)都支持服務器發送事件 (SSE),但 Internet Explorer 不支持。對於需要支持所有瀏覽器的應用程序,WebSockets 或長輪詢可能更合適。
  1. 簡介
  2. 訂閱流:EventSource 對象
  3. 從服務器發送事件
    1. 發送消息事件
    2. 發送自定義事件
    3. 使用重試間隔管理重新連接
    4. 使用 id 字段設置唯一標識符
  4. 處理事件
  5. 處理錯誤
  6. 瀏覽器實現差異
  7. 瀏覽器支持和回退策略

假設您國家的國家籃球隊正在參加世界籃球錦標賽。您想關注比賽,但由於比賽時間與您的工作時間衝突,無法觀看。

幸運的是,您的國家新聞服務擁有一個非常出色的 Web 開發團隊。他們構建了一個體育信息滾動顯示器,每當出現犯規或得分時都會更新。您訪問一個 URL,更新就會直接推送到您的瀏覽器。當然,您會想知道他們是如何做到的。答案是:服務器發送事件。

服務器發送事件是一種使用流將數據和/或 DOM 事件從服務器推送到客戶端的方法。它適用於股票行情、體育比分、航班追踪、電子郵件通知——任何需要定期更新數據的情況。

等等! 我聽到您說,我們不能已經使用 XMLHttpRequest 或 WebSockets 來做到這一點嗎? 是的,可以。但是,這樣做需要擴展這些對象來實現 EventSource 本身的功能。

服務器端注意事項

由於服務器發送事件是數據流,因此它們需要長期連接。您需要使用能夠處理大量同時連接的服務器。當然,事件驅動服務器特別適合流式傳輸事件。這些包括 Node.js、Juggernaut 和 Twisted。對於 Nginx,可以使用 nginx-push-stream-module 模塊。但是,服務器配置不在本文討論範圍之內,並且會因您使用的服務器而異。

讓我們看看如何使用 EventSource 對象訂閱流。然後,我們將看看如何發送和處理事件。

訂閱事件流:EventSource 對象

創建 EventSource 對像很簡單。

<code class="language-javascript">var evtsrc = new EventSource('./url_of/event_stream/',{withCredentials:false});</code>

EventSource 構造函數最多接受兩個參數:

  • 一個 URL 字符串(必需);以及
  • 一個 可選 的字典參數,用於定義 withCredentials 屬性的值。

字典在語法上類似於對象,但它們實際上是具有定義的名稱-值對的關聯數據數組。在本例中,withCredentials 是唯一可能的字典成員。其值可以是 true 或 false。 (要了解有關字典的更多信息,請參閱 Web IDL 規範。)

僅當需要用戶憑據(cookie)的跨域請求時,才需要包含字典參數。到目前為止,沒有瀏覽器支持跨域 EventSource 請求。因此,我們不會在示例中包含第二個參數。

當 EventSource 連接打開時,它將觸發一個 open 事件。我們可以通過設置 onopen 屬性來定義一個處理該事件的函數。

<code class="language-javascript">var evtsrc = new EventSource('./url_of/event_stream/');
evtsrc.onopen = function(openevent){
    // 连接打开时执行的操作
}</code>

如果我們的連接出現問題,將觸發一個錯誤。我們可以使用 onerror 屬性為這些事件定義一個處理程序函數。我們將在“處理錯誤”部分討論一些錯誤事件的原因。

<code class="language-javascript">evtsrc.onerror = function(openevent){
    // 发生错误时执行的操作
}</code>

流式事件默認為消息事件。要處理消息事件,我們可以使用 onmessage 屬性來定義一個處理程序函數。

<code class="language-javascript">evtsrc.onmessage = function(openevent){
    // 接收到消息事件时执行的操作
}</code>

我們還可以使用 addEventListener() 來監聽事件。這是處理自定義事件的唯一方法,正如我們將在“處理事件”部分看到的那樣。

<code class="language-javascript">var onerrorhandler = function(openevent){
    // 执行的操作
}
evtsrc.addEventListener('error',onerrorhandler,false);</code>

要關閉連接,請使用 close() 方法。

<code class="language-javascript">evtsrc.close();</code>

因此,我們創建了 EventSource 對象,並為打開、消息和錯誤事件定義了處理程序。但是,為了使此方法有效,我們需要一個流式傳輸事件的 URL。

從服務器發送事件

服務器發送事件是作為來自 URL 的流的一部分交付的文本片段。為了讓瀏覽器將我們的數據視為流,我們必須:

  • 使用 Content-type 頭部(值為 text/event-stream)來提供內容;
  • 使用 UTF-8 字符編碼。

服務器發送事件的語法很簡單。它由一個或多個冒號分隔的字段名稱-值對組成,後跟一個換行符。字段名稱可以包含四個可能的值之一。

  • data::要發送的信息。
  • event::正在分派的事件類型。
  • id::客戶端重新連接時要使用的事件標識符。
  • retry::瀏覽器嘗試重新連接到 URL 之前應經過多少毫秒。

其中,只有 data 字段是必需的。

發送消息事件

在此示例中,我們將發送一個事件來宣布我們的錦標賽比賽中哪些球隊正在比賽。當瀏覽器接收到此文本時,它將分派一個消息事件。

<code class="language-javascript">var evtsrc = new EventSource('./url_of/event_stream/',{withCredentials:false});</code>

data 字段的值將成為消息事件的 data 屬性的值。如上所述,服務器發送事件默認為消息事件。但正如我們稍後將討論的那樣,我們還可以通過包含 event 字段來分派自定義事件。

我們還可以將幾條數據作為單個事件發送。每塊數據後面都應該跟著一個換行符(換行符、回車符或兩者)。在這裡,我們正在追加一個包含此遊戲位置和出席人數的事件。

<code class="language-javascript">var evtsrc = new EventSource('./url_of/event_stream/');
evtsrc.onopen = function(openevent){
    // 连接打开时执行的操作
}</code>

對於此事件,data 屬性的值將是:Air Canada CentrenToronto, Ontario, CanadanAttendance: 19,800。

請注意事件之間的空行。為了讓客戶端接收事件,事件後面必須跟一個空行。註釋以冒號開頭。

發送自定義事件

除非我們另行指定,否則事件的類型為消息。為此,我們需要包含一個 event 字段。在下面的示例中,我們將向我們的流中添加兩個 startingfive 事件,並將我們的數據作為 JSON 格式的字符串發送。

<code class="language-javascript">evtsrc.onerror = function(openevent){
    // 发生错误时执行的操作
}</code>

在這裡,我們需要監聽 startingfive 事件而不是消息事件。但是,我們的 data 字段仍然會成為事件的 data 屬性的值。

我們將在“處理事件”部分討論 data 屬性和 MessageEvent 接口。

管理連接和重新連接

現在,雖然服務器確實將事件推送到瀏覽器,但現實情況要細微一些。如果服務器保持連接打開,EventSource 請求將是一個擴展的請求。如果它關閉,瀏覽器將等待幾秒鐘,然後重新連接。例如,如果 URL 發送一個文件結束標記,則連接可能會關閉。

每個瀏覽器都設置了自己的默認重新連接間隔。大多數會在 3 到 6 秒後重新連接。但是,您可以通過包含 retry 字段來控制此間隔。 retry 字段指示客戶端在重新連接到 URL 之前應等待多少毫秒。讓我們從上面的示例構建並更改我們的事件以包含 5 秒(5000 毫秒)的重試間隔。

<code class="language-javascript">evtsrc.onmessage = function(openevent){
    // 接收到消息事件时执行的操作
}</code>

事件流可以保持活動狀態,只要客戶端已連接即可。根據您的架構和應用程序,您可能希望服務器定期關閉連接。

使用 id 字段設置唯一標識符

當瀏覽器重新連接到 URL 時,它將接收連接點處可用的任何數據。但是,對於遊戲信息滾動顯示器,我們可能希望讓訪問者了解他或她錯過了什麼。這就是為什麼將 id 設置為每個事件的最佳實踐。在下面的示例中,我們正在發送 id 作為得分事件的一部分。

<code class="language-javascript">var evtsrc = new EventSource('./url_of/event_stream/',{withCredentials:false});</code>

其值應對於流是唯一的。在本例中,我們使用的是投籃得分的時間。

id 字段成為此事件對象的 lastEventId 屬性。但它還有另一個用途。如果連接關閉,瀏覽器將在其下一個請求中包含一個 Last-Event-ID 頭部。將其視為流的書籤。如果存在 Last-Event-ID 頭部,您可以調整應用程序的響應,以便僅發送在其之後的事件。

處理事件

如上所述,所有事件默認為消息事件。每個消息事件都有三個屬性,由 MessageEvent 接口定義。

event.data
返回作為消息事件一部分發送的數據或消息。
event.origin
返回消息的來源,這通常是一個字符串,包含發送消息的方案(例如:http、https)、主機名和端口。
event.lastEventId
返回接收到的最後一個事件的唯一標識符。
每當觸發消息事件時,我們的 onmessage 函數都將被調用。這對於您發送消息事件的應用程序來說效果很好。但是,如果您想發送得分或 startingfive 事件(如我們的示例中所示),其局限性就會變得顯而易見。使用 addEventListener 更靈活。在下面的代碼中,我們正在使用 addEventListener 處理 startingfive 事件。
<code class="language-javascript">var evtsrc = new EventSource('./url_of/event_stream/');
evtsrc.onopen = function(openevent){
    // 连接打开时执行的操作
}</code>

(後續部分,由於篇幅限制,請分段提問。)

以上是服務器範圍事件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn