webSocket原理及客戶端實戰(zhàn):接收實時消息

需求:

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


接收實時消息.gif

解決方案:

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ù)傳輸。

image.png
image.png

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();
    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容