服務(wù)器端推送技術(shù)

源文件:https://w3ctech.com/topic/1754

技術(shù)實(shí)現(xiàn)

1偎窘、ajax輪詢

2、ajax長(zhǎng)輪詢

3噪奄、websocket

4其垄、server-sent-events(SSE)

ajax輪詢

建議不采用,通過(guò) setInterval 定時(shí)發(fā)送請(qǐng)求爽丹。

缺點(diǎn):數(shù)據(jù)同步不及時(shí)筑煮;增加后端處理壓力辛蚊。

setInterval(function() {

?????$.ajax({?

?????????url: 'http://api.3g.qq.com',?

? ? ? ? ?success: function() { //code from here }?

?????});

}, 3000);


ajax長(zhǎng)輪詢

沒(méi)有更新的時(shí)候不再返回空響應(yīng),而且把連接保持到有更新的時(shí)候真仲,客戶端向服務(wù)器發(fā)送Ajax請(qǐng)求嚼隘,服務(wù)器接到請(qǐng)求后hold住連接,直到有新消息才返回響應(yīng)信息并關(guān)閉連接袒餐,客戶端處理完響應(yīng)信息后再向服務(wù)器發(fā)送新的請(qǐng)求飞蛹,通常把這種實(shí)現(xiàn)也叫做comet。

function async() {?

?????$.ajax({?

?????????url: 'http://api.3g.qq.com',

?????????success: function() { async(); //code from here }?

?????});

}

通常的做法是灸眼,在服務(wù)器的程序中加入一個(gè)死循環(huán)卧檐,在循環(huán)中監(jiān)測(cè)數(shù)據(jù)的變動(dòng)。當(dāng)發(fā)現(xiàn)新數(shù)據(jù)時(shí)焰宣,立即將其輸出給瀏覽器并斷開連接霉囚,瀏覽器在收到數(shù)據(jù)后,再次發(fā)起請(qǐng)求以進(jìn)入下一個(gè)周期匕积。


Server-sent-events(SSE)

Server-sent-events(SSE)讓服務(wù)端可以向客戶端流式發(fā)送文本消息盈罐,在實(shí)現(xiàn)上,客戶端瀏覽器中增加EventSource對(duì)象闪唆,使其能通過(guò)事件的方式接收到服務(wù)器推送的消息盅粪,在服務(wù)端,使用長(zhǎng)連接的事件流協(xié)議悄蕾,即請(qǐng)求響應(yīng)時(shí)增加新數(shù)據(jù)流數(shù)據(jù)格式票顾。

非常適應(yīng)于后端數(shù)據(jù)更新頻繁且對(duì)實(shí)時(shí)性要求較高而又不需要客戶端向服務(wù)端通信的場(chǎng)景下。

EventSource API

var source = new EventSource('http://localhost:8080');

source.addEventListener('message', function(e) {? console.log(e.data);}, false);

source.addEventListener('open', function(e) {? // Connection was opened.}, false);

source.addEventListener('error', function(e) {? if (e.readyState == EventSource.CLOSED) {? ? // Connection was closed.? }}, false);

source.addEventListener('userlogin', function(e) {? console.log(e.data);}, false);

客戶端API使用非常簡(jiǎn)單帆调,瀏覽器在支持的情況下會(huì)自動(dòng)處理一切奠骄,包括連接管理接收并解析數(shù)據(jù)到最后觸發(fā)DOM事件,開發(fā)時(shí)只需要關(guān)注業(yè)務(wù)邏輯番刊,EventSource接口還能自動(dòng)重新連接并跟蹤最近接收的消息含鳞,還可以向服務(wù)器發(fā)送上一次接收到消息的ID,以便服務(wù)器重傳丟失的消息并恢復(fù)流芹务。

Event Stream協(xié)議

SSE事件流以流式HTTP響應(yīng)請(qǐng)求蝉绷,客戶端發(fā)起普通的HTTP請(qǐng)求,服務(wù)器以自定義的text/event-stream內(nèi)容類型響應(yīng)锄禽,然后通過(guò)事件傳遞數(shù)據(jù)潜必。

響應(yīng)頭

Content-Type: text/event-stream

Cache-Control: no-cache

Connection: keep-alive

響應(yīng)數(shù)據(jù)格式

id: 123\n

retry: 10000\n

event: userlogin\n

data: {"username": "John123"}\n\n

客戶端通過(guò)EventSource接口發(fā)起連接,服務(wù)器以text/event-stream內(nèi)容類型響應(yīng)沃但,可設(shè)置中斷后重連時(shí)間間隔retry磁滚,數(shù)據(jù)通過(guò)字符串的方式賦值給data字段,也可以指定消息類型給event字段。在客戶端EventSource接口通過(guò)檢查換行分隔符來(lái)解析到來(lái)的數(shù)據(jù)流垂攘,從data字段中獲取數(shù)據(jù)维雇,檢查可選的ID和類型,最后分配事件告知應(yīng)用晒他,如果存在某個(gè)類型吱型,觸發(fā)自定義的事件回調(diào),否則就會(huì)調(diào)用通用的onmessage回調(diào)陨仅。

為了在連接中斷時(shí)恢復(fù)中斷過(guò)程中丟失的消息津滞,服務(wù)器在響應(yīng)時(shí)可以給每條消息關(guān)聯(lián)任意的ID字符串,瀏覽器會(huì)自動(dòng)記錄最后一次接收到消息ID灼伤,并在發(fā)送重新連接請(qǐng)求時(shí)自動(dòng)在HTTP請(qǐng)求頭中追加Last-Event-ID触徐,這樣就可以標(biāo)識(shí)中斷過(guò)程中丟失的消息并重新發(fā)送給客戶端。

優(yōu)點(diǎn)

基于現(xiàn)有http協(xié)議狐赡,實(shí)現(xiàn)簡(jiǎn)單

斷開后自動(dòng)重聯(lián)撞鹉,并可設(shè)置重聯(lián)超時(shí)

派發(fā)任意事件

跨域并有相應(yīng)的安全過(guò)濾

缺點(diǎn)

只能單向通信,服務(wù)器端向客戶端推送事件

事件流協(xié)議只能傳輸U(kuò)TF-8數(shù)據(jù)颖侄,不支持二進(jìn)制流鸟雏。

IE下目前所有不支持EventSource

Tip?如果代理服務(wù)器或中間設(shè)備不支持SSE,會(huì)導(dǎo)致連接失效览祖,正式環(huán)境中使用通過(guò)TLS協(xié)議發(fā)送SSE事件流孝鹊。


WebSocket

WebSocket可以實(shí)現(xiàn)與客戶端與服務(wù)器雙向,基于消息的文本或二進(jìn)制數(shù)據(jù)通信穴墅,主要包括兩個(gè)部分惶室,客戶端WebSocket API及WebSocket協(xié)議。

WebSocket是HTML5出的東西(協(xié)議)玄货,也就是說(shuō)HTTP協(xié)議沒(méi)有變化,或者說(shuō)沒(méi)關(guān)系悼泌,但HTTP是不支持持久連接的(長(zhǎng)連接松捉,循環(huán)連接的不算)首先HTTP有1.1和1.0之說(shuō),也就是所謂的keep-alive馆里,把多個(gè)HTTP請(qǐng)求合并為一個(gè)隘世,但是Websocket其實(shí)是一個(gè)新協(xié)議,跟HTTP協(xié)議基本沒(méi)有關(guān)系鸠踪,只是為了兼容現(xiàn)有瀏覽器的握手規(guī)范而已丙者。

WebSocket API

瀏覽器提供的WebSocket API很簡(jiǎn)單,使用時(shí)無(wú)需關(guān)心連接管理和消息處理等底層細(xì)節(jié)营密,只需要發(fā)起連接械媒,綁定相應(yīng)的事件回調(diào)即可。

var connection = new WebSocket('ws://localhost:8080');

// When the connection is open, send some data to the server

connection.onopen = function () { connection.send('Ping'); // Send the message 'Ping' to the server};

// Log errors

connection.onerror = function (error) { console.log('WebSocket Error ' + error);};

// Log messages from the server

connection.onmessage = function (e) { console.log('Server: ' + e.data);};

// Sending String

connection.send('your message');

// Sending canvas ImageData as ArrayBuffer

var img = canvas_context.getImageData(0, 0, 400, 320);

var binary = new Uint8Array(img.data.length);

for (var i = 0; i < img.data.length; i++) {

????binary[i] = img.data[i];

}

connection.send(binary.buffer);

// Sending file as Blob

var file = document.querySelector('input[type="file"]').files[0];

connection.send(file);

WebSocket資源URL采用了自定議模式,沒(méi)有使用http是為了在非http協(xié)議場(chǎng)景下也能使用纷捞,wss表示使用加密信道通信(TCP + TLS)痢虹,支持接收和發(fā)送文本和二進(jìn)制數(shù)據(jù)。

WebSocket 協(xié)議

WebSocket通信協(xié)議包含兩個(gè)部分主儡,一是開放性HTTP握手連接協(xié)商連接參數(shù)奖唯,二是二進(jìn)制消息分幀機(jī)制(接收消息的文本和二進(jìn)制數(shù)據(jù)傳輸)。它是一個(gè)獨(dú)立完善的協(xié)議糜值,也可以在瀏覽器之外實(shí)現(xiàn)丰捷。

HTTP升級(jí)協(xié)商

WebSocket協(xié)議提供了很多強(qiáng)大的特性:基于消息的通信、自定義的二進(jìn)制分幀層寂汇、子協(xié)議協(xié)商病往、可選的協(xié)議擴(kuò)展,等等健无。即在交換數(shù)據(jù)之前荣恐,客戶端必須與服務(wù)器協(xié)商適當(dāng)?shù)膮?shù)以建立連接。

利用HTTP完成握手有幾個(gè)好處累贤。首先叠穆,讓W(xué)ebSockets與現(xiàn)有HTTP基礎(chǔ)設(shè)施兼容:WebSocket服務(wù)器可以運(yùn)行在80和443 端口上,這通常是對(duì)客戶端唯一開放的端口臼膏。其次硼被,讓我們可以重用并擴(kuò)展HTTP的Upgrade流,為其添加自定義的WebSocket首部渗磅,以完成協(xié)商嚷硫。

請(qǐng)求頭信息

Connection:Upgrade

Sec-WebSocket-Key:eDCPPyPQZq7PiwRcx8SPog==

Sec-WebSocket-Version:13

Upgrade:websocket

響應(yīng)頭信息

HTTP/1.1 101 Switching Protocols

Connection:Upgrade

Sec-WebSocket-Accept:/ZVAP3n6XuqDUoDp416PYUO+ZJc=

Upgrade:websocket

最后,前述握手完成后始鱼,如果握手成功仔掸,該連接就可以用作雙向通信信道交換WebSocket消息。到此医清,客戶端與服務(wù)器之間不會(huì)再發(fā)生HTTP通信起暮,一切由WebSocket?協(xié)議接管。

服務(wù)端實(shí)現(xiàn)

会烙。Node (Socket.IO, WebSocket-Node, ws)

负懦。Java (Jetty)

。Python (Tornado, pywebsocket)

柏腻。...

使用場(chǎng)景

適合于對(duì)數(shù)據(jù)的實(shí)時(shí)性要求比較強(qiáng)的場(chǎng)景纸厉,如通信、股票五嫂、Feed颗品、直播、共享桌面,特別適合于客戶端與服務(wù)頻繁交互的情況下抛猫,如實(shí)時(shí)共享蟆盹、多人協(xié)作等平臺(tái)。

優(yōu)點(diǎn)

闺金。真正的全雙工通信

逾滥。支持跨域設(shè)置(Access-Control-Allow-Origin)

缺點(diǎn)

。采用新的協(xié)議败匹,后端需要單獨(dú)實(shí)現(xiàn)

寨昙。客戶端并不是所有瀏覽器都支持

掀亩。代理服務(wù)器會(huì)有不支持websocket的情況

舔哪。無(wú)超時(shí)處理

。更耗電及占用資源


TIP?代理槽棍、很多現(xiàn)有的HTTP中間設(shè)備可能不理解新的WebSocket協(xié)議捉蚤,而這可能導(dǎo)致各種問(wèn)題,使用時(shí)需要注意炼七,可以使借助TLS缆巧,通過(guò)建立一條端到端的加密信道,可以讓W(xué)ebSocket通信繞過(guò)所有中間代理豌拙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陕悬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子按傅,更是在濱河造成了極大的恐慌捉超,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唯绍,死亡現(xiàn)場(chǎng)離奇詭異拼岳,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)况芒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門裂问,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人牛柒,你說(shuō)我怎么就攤上這事∪” “怎么了皮壁?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)哪审。 經(jīng)常有香客問(wèn)我蛾魄,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任滴须,我火速辦了婚禮舌狗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扔水。我一直安慰自己痛侍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布魔市。 她就那樣靜靜地躺著主届,像睡著了一般。 火紅的嫁衣襯著肌膚如雪待德。 梳的紋絲不亂的頭發(fā)上君丁,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音将宪,去河邊找鬼绘闷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛较坛,可吹牛的內(nèi)容都是我干的印蔗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼燎潮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼喻鳄!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起确封,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤除呵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后爪喘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颜曾,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年秉剑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了泛豪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡侦鹏,死狀恐怖诡曙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情略水,我是刑警寧澤价卤,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站渊涝,受9級(jí)特大地震影響慎璧,放射性物質(zhì)發(fā)生泄漏床嫌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一胸私、第九天 我趴在偏房一處隱蔽的房頂上張望厌处。 院中可真熱鬧,春花似錦岁疼、人聲如沸阔涉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)洒敏。三九已至,卻和暖如春疙驾,著一層夾襖步出監(jiān)牢的瞬間凶伙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工它碎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留函荣,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓扳肛,卻偏偏與公主長(zhǎng)得像傻挂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挖息,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355