SSE
服務(wù)器向?yàn)g覽器推送信息凡人,除了 WebSocket,還有一種方法:Server-Sent Events(以下簡(jiǎn)稱(chēng) SSE)叹阔。本文介紹它的用法挠轴。
SSE 的本質(zhì)
嚴(yán)格地說(shuō),HTTP 協(xié)議無(wú)法做到服務(wù)器主動(dòng)推送信息耳幢。但是忠荞,有一種變通方法,就是服務(wù)器向客戶端聲明帅掘,接下來(lái)要發(fā)送的是流信息(streaming)。
也就是說(shuō)堂油,發(fā)送的不是一次性的數(shù)據(jù)包修档,而是一個(gè)數(shù)據(jù)流,會(huì)連續(xù)不斷地發(fā)送過(guò)來(lái)府框。這時(shí)吱窝,客戶端不會(huì)關(guān)閉連接,會(huì)一直等著服務(wù)器發(fā)過(guò)來(lái)的新的數(shù)據(jù)流,視頻播放就是這樣的例子院峡。本質(zhì)上兴使,這種通信就是以流信息的方式,完成一次用時(shí)很長(zhǎng)的下載照激。
SSE 就是利用這種機(jī)制发魄,使用流信息向?yàn)g覽器推送信息。它基于 HTTP 協(xié)議俩垃,目前除了 IE/Edge励幼,其他瀏覽器都支持。
SSE 的特點(diǎn)
SSE 與 WebSocket 作用相似口柳,都是建立瀏覽器與服務(wù)器之間的通信渠道苹粟,然后服務(wù)器向?yàn)g覽器推送信息。
總體來(lái)說(shuō)跃闹,WebSocket 更強(qiáng)大和靈活嵌削。因?yàn)樗侨p工通道,可以雙向通信望艺;SSE 是單向通道苛秕,只能服務(wù)器向?yàn)g覽器發(fā)送,因?yàn)榱餍畔⒈举|(zhì)上就是下載荣茫。如果瀏覽器向服務(wù)器發(fā)送信息想帅,就變成了另一次 HTTP 請(qǐng)求。
但是啡莉,SSE 也有自己的優(yōu)點(diǎn)港准。
SSE 使用 HTTP 協(xié)議,現(xiàn)有的服務(wù)器軟件都支持咧欣。WebSocket 是一個(gè)獨(dú)立協(xié)議浅缸。
SSE 屬于輕量級(jí),使用簡(jiǎn)單魄咕;WebSocket 協(xié)議相對(duì)復(fù)雜衩椒。
SSE 默認(rèn)支持?jǐn)嗑€重連,WebSocket 需要自己實(shí)現(xiàn)哮兰。
SSE 一般只用來(lái)傳送文本毛萌,二進(jìn)制數(shù)據(jù)需要編碼后傳送,WebSocket 默認(rèn)支持傳送二進(jìn)制數(shù)據(jù)喝滞。
SSE 支持自定義發(fā)送的消息類(lèi)型阁将。
因此,兩者各有特點(diǎn)右遭,適合不同的場(chǎng)合做盅。
三缤削、客戶端 API
3.1 EventSource 對(duì)象
SSE 的客戶端 API 部署在EventSource對(duì)象上。下面的代碼可以檢測(cè)瀏覽器是否支持 SSE吹榴。
if ('EventSource' in window) {
// ...
}
使用 SSE 時(shí)亭敢,瀏覽器首先生成一個(gè)EventSource實(shí)例,向服務(wù)器發(fā)起連接图筹。
var source = new EventSource(url);
上面的url可以與當(dāng)前網(wǎng)址同域帅刀,也可以跨域⌒龀猓跨域時(shí)劝篷,可以指定第二個(gè)參數(shù),打開(kāi)withCredentials屬性民宿,表示是否一起發(fā)送 Cookie娇妓。
var source = new EventSource(url, { withCredentials: true });
EventSource實(shí)例的readyState屬性,表明連接的當(dāng)前狀態(tài)活鹰。該屬性只讀哈恰,可以取以下值。
0:相當(dāng)于常量EventSource.CONNECTING志群,表示連接還未建立着绷,或者斷線正在重連斥难。
1:相當(dāng)于常量EventSource.OPEN脚翘,表示連接已經(jīng)建立缺亮,可以接受數(shù)據(jù)艺挪。
2:相當(dāng)于常量EventSource.CLOSED,表示連接已斷诉濒,且不會(huì)重連汗唱。
3.2 基本用法
連接一旦建立屡拨,就會(huì)觸發(fā)open事件攻冷,可以在onopen屬性定義回調(diào)函數(shù)娃胆。
source.onopen = function (event) {
// ...
};
// 另一種寫(xiě)法
source.addEventListener('open', function (event) {
// ...
}, false);
客戶端收到服務(wù)器發(fā)來(lái)的數(shù)據(jù),就會(huì)觸發(fā)message事件等曼,可以在onmessage屬性的回調(diào)函數(shù)里烦。
source.onmessage = function (event) {
var data = event.data;
// handle message
};
// 另一種寫(xiě)法
source.addEventListener('message', function (event) {
var data = event.data;
// handle message
}, false);
上面代碼中,事件對(duì)象的data屬性就是服務(wù)器端傳回的數(shù)據(jù)(文本格式)禁谦。
如果發(fā)生通信錯(cuò)誤(比如連接中斷)胁黑,就會(huì)觸發(fā)error事件,可以在onerror屬性定義回調(diào)函數(shù)州泊。
source.onerror = function (event) {
// handle error event
};
// 另一種寫(xiě)法
source.addEventListener('error', function (event) {
// handle error event
}, false);
close方法用于關(guān)閉 SSE 連接丧蘸。
source.close();
3.3 自定義事件
默認(rèn)情況下,服務(wù)器發(fā)來(lái)的數(shù)據(jù)拥诡,總是觸發(fā)瀏覽器EventSource實(shí)例的message事件触趴。開(kāi)發(fā)者還可以自定義 SSE 事件,這種情況下渴肉,發(fā)送回來(lái)的數(shù)據(jù)不會(huì)觸發(fā)message事件冗懦。
source.addEventListener('foo', function (event) {
var data = event.data;
// handle message
}, false);
上面代碼中,瀏覽器對(duì) SSE 的foo事件進(jìn)行監(jiān)聽(tīng)仇祭。如何實(shí)現(xiàn)服務(wù)器發(fā)送foo事件披蕉,請(qǐng)看下文。