国产chinesehdxxxx野外,国产av无码专区亚洲av琪琪,播放男人添女人下边视频,成人国产精品一区二区免费看,chinese丰满人妻videos

Javascript Server Sent Events

2023-02-17 10:57 更新

Server-Sent Events 規(guī)范描述了一個(gè)內(nèi)建的類 ?EventSource?,它能保持與服務(wù)器的連接,并允許從中接收事件。

與 WebSocket 類似,其連接是持久的。

但是兩者之間有幾個(gè)重要的區(qū)別:

WebSocket EventSource
雙向:客戶端和服務(wù)端都能交換消息 單向:僅服務(wù)端能發(fā)送消息
二進(jìn)制和文本數(shù)據(jù) 僅文本數(shù)據(jù)
WebSocket 協(xié)議 常規(guī) HTTP 協(xié)議

與 WebSocket 相比,EventSource 是與服務(wù)器通信的一種不那么強(qiáng)大的方式。

我們?yōu)槭裁匆褂盟?

主要原因:簡(jiǎn)單。在很多應(yīng)用中,WebSocket 有點(diǎn)大材小用。

我們需要從服務(wù)器接收一個(gè)數(shù)據(jù)流:可能是聊天消息或者市場(chǎng)價(jià)格等。這正是 EventSource 所擅長(zhǎng)的。它還支持自動(dòng)重新連接,而在 WebSocket 中這個(gè)功能需要我們手動(dòng)實(shí)現(xiàn)。此外,它是一個(gè)普通的舊的 HTTP,不是一個(gè)新協(xié)議。

獲取消息

要開(kāi)始接收消息,我們只需要?jiǎng)?chuàng)建 new EventSource(url) 即可。

瀏覽器將會(huì)連接到 url 并保持連接打開(kāi),等待事件。

服務(wù)器響應(yīng)狀態(tài)碼應(yīng)該為 200,header 為 Content-Type: text/event-stream,然后保持此連接并以一種特殊的格式寫入消息,就像這樣:

data: Message 1

data: Message 2

data: Message 3
data: of two lines
  • ?data:? 后為消息文本,冒號(hào)后面的空格是可選的。
  • 消息以雙換行符 ?\n\n? 分隔。
  • 要發(fā)送一個(gè)換行 ?\n?,我們可以在要換行的位置立即再發(fā)送一個(gè) ?data:?(上面的第三條消息)。

在實(shí)際開(kāi)發(fā)中,復(fù)雜的消息通常是用 JSON 編碼后發(fā)送。換行符在其中編碼為 \n,因此不需要多行 data: 消息。

例如:

data: {"user":"John","message":"First line\n Second line"}

……因此,我們可以假設(shè)一個(gè) data: 只保存了一條消息。

對(duì)于每個(gè)這樣的消息,都會(huì)生成 message 事件:

let eventSource = new EventSource("/events/subscribe");

eventSource.onmessage = function(event) {
  console.log("New message", event.data);
  // 對(duì)于上面的數(shù)據(jù)流將打印三次
};

// 或 eventSource.addEventListener('message', ...)

跨源請(qǐng)求

EventSource 支持跨源請(qǐng)求,就像 fetch 和任何其他網(wǎng)絡(luò)方法。我們可以使用任何 URL:

let source = new EventSource("https://another-site.com/events");

遠(yuǎn)程服務(wù)器將會(huì)獲取到 Origin header,并且必須以 Access-Control-Allow-Origin 響應(yīng)來(lái)處理。

要傳遞憑證(credentials),我們應(yīng)該設(shè)置附加選項(xiàng) withCredentials,就像這樣:

let source = new EventSource("https://another-site.com/events", {
  withCredentials: true
});

更多關(guān)于跨源 header 的詳細(xì)內(nèi)容,請(qǐng)參見(jiàn) Fetch:跨源請(qǐng)求。

重新連接

創(chuàng)建之后,new EventSource 連接到服務(wù)器,如果連接斷開(kāi) —— 則重新連接。

這非常方便,我們不用去關(guān)心重新連接的事情。

每次重新連接之間有一點(diǎn)小的延遲,默認(rèn)為幾秒鐘。

服務(wù)器可以使用 retry: 來(lái)設(shè)置需要的延遲響應(yīng)時(shí)間(以毫秒為單位)。

retry: 15000
data: Hello, I set the reconnection delay to 15 seconds

retry: 既可以與某些數(shù)據(jù)一起出現(xiàn),也可以作為獨(dú)立的消息出現(xiàn)。

在重新連接之前,瀏覽器需要等待那么多毫秒。甚至更長(zhǎng),例如,如果瀏覽器知道(從操作系統(tǒng))此時(shí)沒(méi)有網(wǎng)絡(luò)連接,它會(huì)等到連接出現(xiàn),然后重試。

  • 如果服務(wù)器想要瀏覽器停止重新連接,那么它應(yīng)該使用 HTTP 狀態(tài)碼 204 進(jìn)行響應(yīng)。
  • 如果瀏覽器想要關(guān)閉連接,則應(yīng)該調(diào)用 ?eventSource.close()?:
let eventSource = new EventSource(...);

eventSource.close();

并且,如果響應(yīng)具有不正確的 Content-Type 或者其 HTTP 狀態(tài)碼不是 301,307,200 和 204,則不會(huì)進(jìn)行重新連接。在這種情況下,將會(huì)發(fā)出 "error" 事件,并且瀏覽器不會(huì)重新連接。

請(qǐng)注意:

當(dāng)連接最終被關(guān)閉時(shí),就無(wú)法“重新打開(kāi)”它。如果我們想要再次連接,只需要?jiǎng)?chuàng)建一個(gè)新的 EventSource

消息 id

當(dāng)一個(gè)連接由于網(wǎng)絡(luò)問(wèn)題而中斷時(shí),客戶端和服務(wù)器都無(wú)法確定哪些消息已經(jīng)收到哪些沒(méi)有收到。

為了正確地恢復(fù)連接,每條消息都應(yīng)該有一個(gè) ?id? 字段,就像這樣:

data: Message 1
id: 1

data: Message 2
id: 2

data: Message 3
data: of two lines
id: 3

當(dāng)收到具有 id 的消息時(shí),瀏覽器會(huì):

  • 將屬性 ?eventSource.lastEventId? 設(shè)置為其值。
  • 重新連接后,發(fā)送帶有 ?id? 的 header ?Last-Event-ID?,以便服務(wù)器可以重新發(fā)送后面的消息。

把 ?id:? 放在 ?data:? 后

請(qǐng)注意:id 被服務(wù)器附加到 data 消息后,以確保在收到消息后 lastEventId 會(huì)被更新。

連接狀態(tài):readyState

EventSource 對(duì)象有 readyState 屬性,該屬性具有下列值之一:

EventSource.CONNECTING = 0; // 連接中或者重連中
EventSource.OPEN = 1;       // 已連接
EventSource.CLOSED = 2;     // 連接已關(guān)閉

對(duì)象創(chuàng)建完成或者連接斷開(kāi)后,它始終是 EventSource.CONNECTING(等于 0)。

我們可以查詢?cè)搶傩砸粤私?nbsp;EventSource 的狀態(tài)。

Event 類型

默認(rèn)情況下 ?EventSource? 對(duì)象生成三個(gè)事件:

  • ?message? —— 收到消息,可以用 ?event.data? 訪問(wèn)。
  • ?open? —— 連接已打開(kāi)。
  • ?error? —— 無(wú)法建立連接,例如,服務(wù)器返回 HTTP 500 狀態(tài)碼。

服務(wù)器可以在事件開(kāi)始時(shí)使用 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}`);
});

完整示例

服務(wù)器依次發(fā)送 1,2,3,最后發(fā)送 bye 并斷開(kāi)連接。

然后瀏覽器會(huì)自動(dòng)重新連接。

下載鏈接

總結(jié)

?EventSource? 對(duì)象自動(dòng)建立一個(gè)持久的連接,并允許服務(wù)器通過(guò)這個(gè)連接發(fā)送消息。

它提供了:

  • 在可調(diào)的 ?retry? 超時(shí)內(nèi)自動(dòng)重新連接。
  • 用于恢復(fù)事件的消息 id,重新連接后,最后接收到的標(biāo)識(shí)符被在 ?Last-Event-ID? header 中發(fā)送出去。
  • 當(dāng)前狀態(tài)位于 ?readyState? 屬性中。

這使得 EventSource 成為 WebSocket 的一個(gè)可行的替代方案,因?yàn)?nbsp;WebSocket 更底層(low-level),且缺乏這樣的內(nèi)建功能(盡管它們可以被實(shí)現(xiàn))。

在很多實(shí)際應(yīng)用中,EventSource 的功能就已經(jīng)夠用了。

EventSource 在所有現(xiàn)代瀏覽器(除了 IE)中都得到了支持。

語(yǔ)法:

let source = new EventSource(url, [credentials]);

第二個(gè)參數(shù)只有一個(gè)可選項(xiàng):{ withCredentials: true },它允許發(fā)送跨源憑證。

總體跨源安全性與 fetch 以及其他網(wǎng)絡(luò)方法相同。

EventSource 對(duì)象的屬性

?readyState ?

當(dāng)前連接狀態(tài):為 ?EventSource.CONNECTING (=0)?,?EventSource.OPEN (=1)?,?EventSource.CLOSED (=2)? 三者之一。

?lastEventId ?

最后接收到的 ?id?。重新連接后,瀏覽器在 header ?Last-Event-ID? 中發(fā)送此 id。

EventSource 對(duì)象的方法

?close() ?

關(guān)閉連接。

EventSource 對(duì)象的事件

?message ?

接收到的消息,消息數(shù)據(jù)在 ?event.data? 中。

?open ?

連接已建立。

?error ?

如果發(fā)生錯(cuò)誤,包括連接丟失(將會(huì)自動(dòng)重連)以及其他致命錯(cuò)誤。我們可以檢查 ?readyState? 以查看是否正在嘗試重新連接。

服務(wù)器可以在 event: 中設(shè)置自定義事件名稱。應(yīng)該使用 addEventListener 來(lái)處理此類事件,而不是使用 on<event>

服務(wù)器響應(yīng)格式

服務(wù)器發(fā)送由 \n\n 分隔的消息。

一條消息可能有以下字段:

  • ?data:? —— 消息體(body),一系列多個(gè) ?data? 被解釋為單個(gè)消息,各個(gè)部分之間由 ?\n? 分隔。
  • ?id:? —— 更新 ?lastEventId?,重連時(shí)以 ?Last-Event-ID? 發(fā)送此 id。
  • ?retry:? —— 建議重連的延遲,以 ms 為單位。無(wú)法通過(guò) JavaScript 進(jìn)行設(shè)置。
  • ?event:? —— 事件名,必須在 ?data:? 之前。

一條消息可以按任何順序包含一個(gè)或多個(gè)字段,但是 id: 通常排在最后。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)