长连接/websocket/SSE等主流服务器推送技术比较
最近做的某個(gè)項(xiàng)目有個(gè)需求,需要實(shí)時(shí)提醒client端有線上訂單消息。所以保持客戶端和服務(wù)器端的信息同步是關(guān)鍵要素,對(duì)此我們了解了可實(shí)現(xiàn)的方式。本文將介紹web常用的幾種方式,希望給需要服務(wù)器端推送消息的同學(xué)在選型上有一點(diǎn)啟發(fā)。
一、推送技術(shù)常用的集中實(shí)現(xiàn)的實(shí)現(xiàn)方式
1.1 短連接輪詢:
前端用定時(shí)器,每間隔一段時(shí)間發(fā)送請(qǐng)求來獲取數(shù)據(jù)是否更新,這種方式可兼容ie和支持高級(jí)瀏覽器。通常采取setInterval或者setTimeout實(shí)現(xiàn)。
(輪詢示意圖)通過遞歸的方法,在獲取到數(shù)據(jù)后每隔一定時(shí)間再次發(fā)送請(qǐng)求,這樣雖然無法保證兩次請(qǐng)求間隔為指定時(shí)間,但是獲取的數(shù)據(jù)順序得到保證。
- 缺點(diǎn):
1、頁面會(huì)出現(xiàn)‘假死’
setTimeout在等到每次EventLoop時(shí),都要判斷是否到指定時(shí)間,直到時(shí)間到再執(zhí)行函數(shù),一旦遇到頁面有大量任務(wù)或者返回時(shí)間特別耗時(shí),頁面就會(huì)出現(xiàn)‘假死’,無法響應(yīng)用戶行為。
2、無謂的網(wǎng)絡(luò)傳輸
當(dāng)客戶端按固定頻率向服務(wù)器發(fā)起請(qǐng)求,數(shù)據(jù)可能并沒有更新,浪費(fèi)服務(wù)器資源。
1.2 長(zhǎng)輪詢:
客戶端像傳統(tǒng)輪詢一樣從服務(wù)端請(qǐng)求數(shù)據(jù),服務(wù)端會(huì)阻塞請(qǐng)求不會(huì)立刻返回,直到有數(shù)據(jù)或超時(shí)才返回給客戶端,然后關(guān)閉連接,客戶端處理完響應(yīng)信息后再向服務(wù)器發(fā)送新的請(qǐng)求。
(輪詢示意圖)長(zhǎng)輪詢解決了頻繁的網(wǎng)絡(luò)請(qǐng)求浪費(fèi)服務(wù)器資源可以及時(shí)返回給瀏覽器。
- 缺點(diǎn):
1、保持連接會(huì)消耗資源。
2、服務(wù)器沒有返回有效數(shù)據(jù),程序超時(shí)。
1.3 iframe流:
iframe流方式是在頁面中插入一個(gè)隱藏的iframe,利用其src屬性在服務(wù)器和客戶端之間創(chuàng)建一條長(zhǎng)連接,服務(wù)器向iframe傳輸數(shù)據(jù)(通常是HTML,內(nèi)有負(fù)責(zé)插入信息的javascript),來實(shí)時(shí)更新頁面。
- 前端實(shí)現(xiàn)步驟:
1、Iframe設(shè)置為不顯示。
2、src設(shè)為請(qǐng)求的數(shù)據(jù)地址。
3、定義個(gè)父級(jí)函數(shù)用戶讓iframe子頁面調(diào)用傳數(shù)據(jù)給父頁面。
4、定義onload事件,服務(wù)器timeout后再次重新加載iframe。
- 后端輸出內(nèi)容:
當(dāng)有新消息時(shí)服務(wù)端會(huì)向iframe中輸入一段js代碼.:println("<script>父級(jí)函數(shù)('" + 數(shù)據(jù) +"<br>')</script>”);用于調(diào)用父級(jí)函數(shù)傳數(shù)據(jù)。
- 優(yōu)點(diǎn):
iframe流方式的優(yōu)點(diǎn)是瀏覽器兼容好,Google公司在一些產(chǎn)品中使用了iframe流,如Google Talk。
- 缺點(diǎn):
1、IE、Mozilla Firefox會(huì)顯示加載沒有完成,圖標(biāo)會(huì)不停旋轉(zhuǎn)。
2、服務(wù)器維護(hù)一個(gè)長(zhǎng)連接會(huì)增加開銷。
1.4 WebSocket:
WebSocket是一種全新的協(xié)議,隨著HTML5草案的不斷完善,越來越多的現(xiàn)代瀏覽器開始全面支持WebSocket技術(shù)了,它將TCP的Socket(套接字)應(yīng)用在了webpage上,從而使通信雙方建立起一個(gè)保持在活動(dòng)狀態(tài)連接通道。
- 原理:
WebSocket協(xié)議是借用HTTP協(xié)議的101 switchprotocol(服務(wù)器根據(jù)客戶端的指定,將協(xié)議轉(zhuǎn)換成為 Upgrade首部所列的協(xié)議)來達(dá)到協(xié)議轉(zhuǎn)換的,從HTTP協(xié)議切換成WebSocket通信協(xié)議。
- 具體連接方式:
通過在請(qǐng)求頭中增加 upgrade:websocket 及通信密鑰(Sec-WebSocket-Key),使雙方握手成功,建立全雙工通信。
(WebSocket客戶端連接報(bào)文) (WebSocket服務(wù)端響應(yīng)報(bào)文)- 通信過程:
websocket是純事件驅(qū)動(dòng)的,一旦 WebSocket 連接建立后,通過監(jiān)聽事件可以處理到來的數(shù)據(jù)和改變的連接狀態(tài)。數(shù)據(jù)都以幀序列的形式傳輸。服務(wù)端發(fā)送數(shù)據(jù)后,消息和事件會(huì)異步到達(dá)。WebSocket編程遵循一個(gè)異步編程模型,只需要對(duì)WebSocket對(duì)象增加回調(diào)函數(shù)就可以監(jiān)聽事件。
(websocket示意圖)前端:
服務(wù)端:
1.5 Server-sent Events(sse):
sse與長(zhǎng)輪詢機(jī)制類似,區(qū)別是每個(gè)連接不只發(fā)送一個(gè)消息??蛻舳税l(fā)送一個(gè)請(qǐng)求,服務(wù)端保持這個(gè)連接直到有新消息發(fā)送回客戶端,仍然保持著連接,這樣連接就可以消息的再次發(fā)送,由服務(wù)器單向發(fā)送給客戶端。
- 原理:
SSE本質(zhì)是發(fā)送的不是一次性的數(shù)據(jù)包,而是一個(gè)數(shù)據(jù)流??梢允褂?HTTP 301 和 307 重定向與正常的 HTTP 請(qǐng)求一樣。服務(wù)端連續(xù)不斷的發(fā)送,客戶端不會(huì)關(guān)閉連接,如果連接斷開,瀏覽器會(huì)嘗試重新連接。如果連接被關(guān)閉,客戶端可以被告知使用 HTTP 204 無內(nèi)容響應(yīng)代碼停止重新連接。
sse只適用于高級(jí)瀏覽器,ie不支持。因?yàn)閕e上的XMLHttpRequest對(duì)象不支持獲取部分的響應(yīng)內(nèi)容,只有在響應(yīng)完成之后才能獲取其內(nèi)容。
二、常用實(shí)現(xiàn)的對(duì)比
三、項(xiàng)目選型
Websocket需要服務(wù)器重新部署,sse可以利用原先的http協(xié)議,而我們項(xiàng)目是在高級(jí)瀏覽器環(huán)境,場(chǎng)景是需要服務(wù)器單向發(fā)送給客戶端,所以sse更符合我們的需求。
四、項(xiàng)目實(shí)踐
A應(yīng)用下單完成后,把訂單消息放入到redis緩存中,B應(yīng)用去獲取redis緩存信息判斷是否是新訂單,否的情況輪詢r(jià)edis緩存,是的情況消息推送給前端。
(后端流程圖)客戶端:
然后使用onmessage事件來獲取消息
服務(wù)端可以自定義類型的事件,對(duì)于這些事件,可以使用addEventListener來獲取。
服務(wù)端:
內(nèi)容與普通的Controller差不多。只不過相應(yīng)的方法在路由配置時(shí),將produces屬性的文本類型設(shè)置成“text/event-stream”即可。
首先通過設(shè)置唯一標(biāo)識(shí)符+venueid,獲取相應(yīng)場(chǎng)館保存在redis中的訂單。
常見問題及解決方案:
1、怎么確定推過來的消息是新消息
這里我們?cè)O(shè)置了一個(gè)本地緩存,用來存放上一次從redis中獲取的信息,和當(dāng)前從redis獲取的信息做對(duì)比,不同,則認(rèn)為是新信息返回給客戶端并標(biāo)識(shí)是新數(shù)據(jù)。
2、刷新頁面原先推送過來的消息消失了
因?yàn)樵谕ㄟ^redis和本地緩存對(duì)比的時(shí)候沒有區(qū)別所以不會(huì)推送,這里前端設(shè)置一個(gè)隨機(jī)數(shù)num,在存入本地緩存時(shí)key值多加了num的區(qū)分。
3、解決容器超時(shí)的問題
后端容器的單個(gè)連接超時(shí)時(shí)間為2分鐘,后端每隔3秒鐘會(huì)輪詢一次redis,到第20次的時(shí)候,會(huì)推送個(gè)帶有個(gè)標(biāo)識(shí)的數(shù)據(jù)。
4、接口防刷方案
后端記錄每次獲取到的num值判斷總數(shù)vnum,超過一定數(shù)量返回http 204斷開連接。
總結(jié)
對(duì)于簡(jiǎn)單的推送需求又不考慮兼容低版本瀏覽器,推薦使用server-sent Events。
如果需要多條雙向數(shù)據(jù)實(shí)時(shí)交互或需要二進(jìn)制傳輸,推薦websocket。
對(duì)于還要考慮低版本瀏覽器,那么還是用輪詢來實(shí)現(xiàn)功能。
【作者介紹】本文由攜程市場(chǎng)營銷研發(fā)部武藝嬙和王宇星以及張子祥共同撰寫,武藝嬙在市場(chǎng)營銷研發(fā)部負(fù)責(zé)前端,王宇星和張子祥在市場(chǎng)營銷研發(fā)部負(fù)責(zé)java后端。
https://zhuanlan.zhihu.com/p/31297574
總結(jié)
以上是生活随笔為你收集整理的长连接/websocket/SSE等主流服务器推送技术比较的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 京东JIMI用户未来意图预测技术揭秘
- 下一篇: Android工程模块化平台的设计