需求:
需求實現(xiàn)監(jiān)聽服務(wù)端推送過來的消息,效果見下圖:
用戶某一個動作觸發(fā)消息發(fā)送,在監(jiān)聽接口收到消息并展示出來。

解決方案:
ajax輪詢(短輪詢)
原理:客戶端每隔幾秒就發(fā)送一次請求,服務(wù)器接到請求后馬上返回響應(yīng)信息并關(guān)閉連接。
優(yōu)點:程序編寫比較容易。
缺點:請求次數(shù)多,請求中有大半是無用,浪費帶寬和服務(wù)器資源。
long poll (長輪詢)
原理:跟ajax輪詢差不多,都是采用輪詢的方式,區(qū)別在于:服務(wù)端收到請求后,檢測數(shù)據(jù)是否有新數(shù)據(jù),有則立即返回并關(guān)閉,無則掛起一直不返回Response直到超時關(guān)閉。關(guān)閉后客戶端再次發(fā)起請求建立連接,周而復(fù)始。
優(yōu)點:客戶端的請求次數(shù)會大量減少
缺點:服務(wù)端請求掛起同樣會導(dǎo)致資源的浪費
小結(jié):
1.HTTP協(xié)議是基于請求/響應(yīng)模式的,因此只要服務(wù)端給了響應(yīng),本次HTTP連接就結(jié)束了。
2.Ajax輪詢與long poll都屬于不斷發(fā)送http請求,然后等待服務(wù)器處理,可以看到http協(xié)議一個特點,被動性!
webSocket
webSocket是html5一種新的協(xié)議,實現(xiàn)了瀏覽器與服務(wù)器之間的全雙工通信,能很好的節(jié)省服務(wù)器資源與帶寬,并在服務(wù)器端與瀏覽器端實現(xiàn)實時通行,他建立在TCP之上, 同http一樣,通過tcp來傳輸數(shù)據(jù)。
WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。在 WebSocket API 中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進行雙向數(shù)據(jù)傳輸。


webSocket客戶端實例
使用如下的代碼可以實現(xiàn)上面圖片收到實時消息的效果。
//實時消息
startWebSocket(){
let this_=this;
let wsUrl=urlConfig.wsUrl+localStorage.getItem("access_token");//websocket接口地址
let ws = new WebSocket(wsUrl);
ws.onclose = function () {
this_.reConnect(wsUrl);//重新連接
console.log("連接已關(guān)閉 "+new Date());
};
ws.onerror = function () {
this_.reConnect(wsUrl);//重新連接
console.log("連接異常 "+new Date());
};
ws.onopen = function () {
heartCheck.reset().start();//開始心跳檢測
console.log("連接成功 "+new Date());
};
ws.onmessage = function (e) {
heartCheck.reset().start();//開始心跳檢測
let data = JSON.parse(e.data);
this_.onMessageNotice(data);//獲取到數(shù)據(jù)的回調(diào)
};
/*心跳檢測:
1.如果當前連接著(onopen或onMessage),就開始心跳檢測,即設(shè)置定時器一段時間后發(fā)送一條數(shù)據(jù),發(fā)送后再過一段時間關(guān)閉連接;
如果在關(guān)閉之前,后端正常返回數(shù)據(jù)(會觸發(fā)onMessage),會重置心跳檢測就一直不會關(guān)閉連接。
2.如果當前異常或關(guān)閉(onclose,onerror),就重新建立連接;
*/
let heartCheck = {
timeout: 180000, //3分鐘發(fā)一次心跳
timeoutObj: null,//定時器:延時發(fā)送一次心跳
serverTimeoutObj: null,//定時器:延時檢測后端是否返回數(shù)據(jù),如返回則還連著,如未返回則后端斷了
reset: function(){
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function(){
let this_ = this;
this.timeoutObj = setTimeout(function(){
ws.send("peng");
console.log("peng");
this_.serverTimeoutObj = setTimeout(function(){//如果超過一定時間還沒重置,說明后端主動斷開了
ws.close(); //如果onclose會執(zhí)行reconnect,我們執(zhí)行ws.close()就行了.如果直接執(zhí)行reconnect 會觸發(fā)onclose導(dǎo)致重連兩次
}, this_.timeout)
}, this.timeout)
}
};
}
//重新連接websocket
reConnect(url) {
let this_=this;
if(this.lockReconnect) return;
this.setState({
lockReconnect:true//上鎖
});
setTimeout(function () { //沒連接上會一直重連,設(shè)置延遲避免請求過多
this_.startWebSocket(url);
this_.setState({
lockReconnect:false//開鎖
});
}, 5000);
}
//收到消息的回調(diào)
onMessageNotice(data){
notification.info({//antd 中的組件
message: "這是一條消息",
description: "消息描述",
});
//收到消息重新獲取消息列表
this.getNewsList();
//播放聲音
this.refs.audio.play();
}