核心要點
Content-type
頭部(值為 text/event-stream
)和 UTF-8 字符編碼來提供內容。服務器發送事件的語法包括數據、事件類型、事件標識符和重試間隔。 onmessage
函數(僅用於發送消息事件的應用程序),但 addEventListener
方法對於處理自定義事件更靈活。 假設您國家的國家籃球隊正在參加世界籃球錦標賽。您想關注比賽,但由於比賽時間與您的工作時間衝突,無法觀看。
幸運的是,您的國家新聞服務擁有一個非常出色的 Web 開發團隊。他們構建了一個體育信息滾動顯示器,每當出現犯規或得分時都會更新。您訪問一個 URL,更新就會直接推送到您的瀏覽器。當然,您會想知道他們是如何做到的。答案是:服務器發送事件。
服務器發送事件是一種使用流將數據和/或 DOM 事件從服務器推送到客戶端的方法。它適用於股票行情、體育比分、航班追踪、電子郵件通知——任何需要定期更新數據的情況。
等等!
我聽到您說,我們不能已經使用 XMLHttpRequest 或 WebSockets 來做到這一點嗎?
是的,可以。但是,這樣做需要擴展這些對象來實現 EventSource 本身的功能。
由於服務器發送事件是數據流,因此它們需要長期連接。您需要使用能夠處理大量同時連接的服務器。當然,事件驅動服務器特別適合流式傳輸事件。這些包括 Node.js、Juggernaut 和 Twisted。對於 Nginx,可以使用 nginx-push-stream-module 模塊。但是,服務器配置不在本文討論範圍之內,並且會因您使用的服務器而異。
讓我們看看如何使用 EventSource 對象訂閱流。然後,我們將看看如何發送和處理事件。
創建 EventSource 對像很簡單。
<code class="language-javascript">var evtsrc = new EventSource('./url_of/event_stream/',{withCredentials:false});</code>
EventSource 構造函數最多接受兩個參數:
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
)來提供內容;服務器發送事件的語法很簡單。它由一個或多個冒號分隔的字段名稱-值對組成,後跟一個換行符。字段名稱可以包含四個可能的值之一。
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>
事件流可以保持活動狀態,只要客戶端已連接即可。根據您的架構和應用程序,您可能希望服務器定期關閉連接。
當瀏覽器重新連接到 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 接口定義。
onmessage
函數都將被調用。這對於您只發送消息事件的應用程序來說效果很好。但是,如果您想發送得分或 startingfive
事件(如我們的示例中所示),其局限性就會變得顯而易見。使用 addEventListener
更靈活。在下面的代碼中,我們正在使用 addEventListener
處理 startingfive
事件。
<code class="language-javascript">var evtsrc = new EventSource('./url_of/event_stream/'); evtsrc.onopen = function(openevent){ // 连接打开时执行的操作 }</code>
(後續部分,由於篇幅限制,請分段提問。)
以上是服務器範圍事件的詳細內容。更多資訊請關注PHP中文網其他相關文章!