W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
Server-Sent Events 規(guī)范描述了一個內建的類 ?EventSource
?,它能保持與服務器的連接,并允許從中接收事件。
與 WebSocket
類似,其連接是持久的。
但是兩者之間有幾個重要的區(qū)別:
WebSocket
|
EventSource
|
---|---|
雙向:客戶端和服務端都能交換消息 | 單向:僅服務端能發(fā)送消息 |
二進制和文本數(shù)據(jù) | 僅文本數(shù)據(jù) |
WebSocket 協(xié)議 | 常規(guī) HTTP 協(xié)議 |
與 WebSocket
相比,EventSource
是與服務器通信的一種不那么強大的方式。
我們?yōu)槭裁匆褂盟?
主要原因:簡單。在很多應用中,WebSocket
有點大材小用。
我們需要從服務器接收一個數(shù)據(jù)流:可能是聊天消息或者市場價格等。這正是 EventSource
所擅長的。它還支持自動重新連接,而在 WebSocket
中這個功能需要我們手動實現(xiàn)。此外,它是一個普通的舊的 HTTP,不是一個新協(xié)議。
要開始接收消息,我們只需要創(chuàng)建 new EventSource(url)
即可。
瀏覽器將會連接到 url
并保持連接打開,等待事件。
服務器響應狀態(tài)碼應該為 200,header 為 Content-Type: text/event-stream
,然后保持此連接并以一種特殊的格式寫入消息,就像這樣:
data: Message 1
data: Message 2
data: Message 3
data: of two lines
data:
? 后為消息文本,冒號后面的空格是可選的。\n\n
? 分隔。\n
?,我們可以在要換行的位置立即再發(fā)送一個 ?data:
?(上面的第三條消息)。在實際開發(fā)中,復雜的消息通常是用 JSON 編碼后發(fā)送。換行符在其中編碼為 \n
,因此不需要多行 data:
消息。
例如:
data: {"user":"John","message":"First line\n Second line"}
……因此,我們可以假設一個 data:
只保存了一條消息。
對于每個這樣的消息,都會生成 message
事件:
let eventSource = new EventSource("/events/subscribe");
eventSource.onmessage = function(event) {
console.log("New message", event.data);
// 對于上面的數(shù)據(jù)流將打印三次
};
// 或 eventSource.addEventListener('message', ...)
EventSource
支持跨源請求,就像 fetch
和任何其他網(wǎng)絡方法。我們可以使用任何 URL:
let source = new EventSource("https://another-site.com/events");
遠程服務器將會獲取到 Origin
header,并且必須以 Access-Control-Allow-Origin
響應來處理。
要傳遞憑證(credentials),我們應該設置附加選項 withCredentials
,就像這樣:
let source = new EventSource("https://another-site.com/events", {
withCredentials: true
});
更多關于跨源 header 的詳細內容,請參見 Fetch:跨源請求。
創(chuàng)建之后,new EventSource
連接到服務器,如果連接斷開 —— 則重新連接。
這非常方便,我們不用去關心重新連接的事情。
每次重新連接之間有一點小的延遲,默認為幾秒鐘。
服務器可以使用 retry:
來設置需要的延遲響應時間(以毫秒為單位)。
retry: 15000
data: Hello, I set the reconnection delay to 15 seconds
retry:
既可以與某些數(shù)據(jù)一起出現(xiàn),也可以作為獨立的消息出現(xiàn)。
在重新連接之前,瀏覽器需要等待那么多毫秒。甚至更長,例如,如果瀏覽器知道(從操作系統(tǒng))此時沒有網(wǎng)絡連接,它會等到連接出現(xiàn),然后重試。
eventSource.close()
?:let eventSource = new EventSource(...);
eventSource.close();
并且,如果響應具有不正確的 Content-Type
或者其 HTTP 狀態(tài)碼不是 301,307,200 和 204,則不會進行重新連接。在這種情況下,將會發(fā)出 "error"
事件,并且瀏覽器不會重新連接。
請注意:
當連接最終被關閉時,就無法“重新打開”它。如果我們想要再次連接,只需要創(chuàng)建一個新的
EventSource
。
當一個連接由于網(wǎng)絡問題而中斷時,客戶端和服務器都無法確定哪些消息已經(jīng)收到哪些沒有收到。
為了正確地恢復連接,每條消息都應該有一個 ?id
? 字段,就像這樣:
data: Message 1
id: 1
data: Message 2
id: 2
data: Message 3
data: of two lines
id: 3
當收到具有 id
的消息時,瀏覽器會:
eventSource.lastEventId
? 設置為其值。id
? 的 header ?Last-Event-ID
?,以便服務器可以重新發(fā)送后面的消息。把 ?
id:
? 放在 ?data:
? 后請注意:
id
被服務器附加到data
消息后,以確保在收到消息后lastEventId
會被更新。
EventSource
對象有 readyState
屬性,該屬性具有下列值之一:
EventSource.CONNECTING = 0; // 連接中或者重連中
EventSource.OPEN = 1; // 已連接
EventSource.CLOSED = 2; // 連接已關閉
對象創(chuàng)建完成或者連接斷開后,它始終是 EventSource.CONNECTING
(等于 0
)。
我們可以查詢該屬性以了解 EventSource
的狀態(tài)。
默認情況下 ?EventSource
? 對象生成三個事件:
message
? —— 收到消息,可以用 ?event.data
? 訪問。open
? —— 連接已打開。error
? —— 無法建立連接,例如,服務器返回 HTTP 500 狀態(tài)碼。服務器可以在事件開始時使用 event: ...
指定另一種類型事件。
例如:
event: join
data: Bob
data: Hello
event: leave
data: Bob
要處理自定義事件,我們必須使用 addEventListener
而非 onmessage
:
eventSource.addEventListener('join', event => {
alert(`Joined ${event.data}`);
});
eventSource.addEventListener('message', event => {
alert(`Said: ${event.data}`);
});
eventSource.addEventListener('leave', event => {
alert(`Left ${event.data}`);
});
服務器依次發(fā)送 1
,2
,3
,最后發(fā)送 bye
并斷開連接。
然后瀏覽器會自動重新連接。
?EventSource
? 對象自動建立一個持久的連接,并允許服務器通過這個連接發(fā)送消息。
它提供了:
retry
? 超時內自動重新連接。Last-Event-ID
? header 中發(fā)送出去。readyState
? 屬性中。這使得 EventSource
成為 WebSocket
的一個可行的替代方案,因為 WebSocket
更底層(low-level),且缺乏這樣的內建功能(盡管它們可以被實現(xiàn))。
在很多實際應用中,EventSource
的功能就已經(jīng)夠用了。
EventSource
在所有現(xiàn)代瀏覽器(除了 IE)中都得到了支持。
語法:
let source = new EventSource(url, [credentials]);
第二個參數(shù)只有一個可選項:{ withCredentials: true }
,它允許發(fā)送跨源憑證。
總體跨源安全性與 fetch
以及其他網(wǎng)絡方法相同。
?readyState
?
當前連接狀態(tài):為 ?EventSource.CONNECTING (=0)
?,?EventSource.OPEN (=1)
?,?EventSource.CLOSED (=2)
? 三者之一。
?lastEventId
?
最后接收到的 ?id
?。重新連接后,瀏覽器在 header ?Last-Event-ID
? 中發(fā)送此 id。
?close()
?
關閉連接。
?message
?
接收到的消息,消息數(shù)據(jù)在 ?event.data
? 中。
?open
?
連接已建立。
?error
?
如果發(fā)生錯誤,包括連接丟失(將會自動重連)以及其他致命錯誤。我們可以檢查 ?readyState
? 以查看是否正在嘗試重新連接。
服務器可以在 event:
中設置自定義事件名稱。應該使用 addEventListener
來處理此類事件,而不是使用 on<event>
。
服務器發(fā)送由 \n\n
分隔的消息。
一條消息可能有以下字段:
data:
? —— 消息體(body),一系列多個 ?data
? 被解釋為單個消息,各個部分之間由 ?\n
? 分隔。id:
? —— 更新 ?lastEventId
?,重連時以 ?Last-Event-ID
? 發(fā)送此 id。retry:
? —— 建議重連的延遲,以 ms 為單位。無法通過 JavaScript 進行設置。event:
? —— 事件名,必須在 ?data:
? 之前。一條消息可以按任何順序包含一個或多個字段,但是 id:
通常排在最后。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: