vue中使用WebSocket及心跳機制

一、WebSocket簡介

WebSocket是HTML5開始提供的一種瀏覽器與服務(wù)器進行全雙工通訊的網(wǎng)絡(luò)技術(shù),屬于應(yīng)用層協(xié)議。
WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。

二、WebSocket事件與方法

1、創(chuàng)建WebSocket實例

    var socketObj;
    if ("WebSocket" in window) {
      socketObj = new WebSocket(webSocketLink);
    } else if ("MozWebSocket" in window) {
      socketObj = new MozWebSocket(webSocketLink);
    }

2、WebSocket 事件

事件.png

3、WebSocket 方法

方法.png

三、WebSocket的心跳重連機制

1、問題

(1)websocket在連接后,如果長時間服務(wù)端和客戶端不發(fā)消息,服務(wù)端會把websocket給斷開。
(2)存在網(wǎng)絡(luò)忽然斷開的情況,這時服務(wù)器端并沒有觸發(fā)onclose的事件。服務(wù)器會繼續(xù)向客戶端發(fā)送多余的信息,這些數(shù)據(jù)會丟失。

2、心跳重連機制

為了解決上面的問題,就需要?種機制來檢測客戶端和服務(wù)端是否處于正常的連接狀態(tài)。因此就有了websocket的心跳機制。

?跳機制是客戶端每隔?段時間會向服務(wù)端發(fā)送?個數(shù)據(jù)包,告訴服務(wù)端自己還活著,同時客戶端會根據(jù)服務(wù)端是否會回傳?個數(shù)據(jù)包來確定服務(wù)端是否還活著。
如果客戶端沒有收到回復(fù),表示websocket斷開連接或者網(wǎng)絡(luò)出現(xiàn)問題,就需要重連。

四、實際使用

詳細代碼如下:

<template>
  <div></div>
</template>
<script>
export default {
  data() {
    return {
      // websocket相關(guān)
      socketObj: "", // websocket實例對象
      //心跳檢測
      heartCheck: {
        vueThis: this, // vue實例
        timeout: 10000, // 超時時間
        timeoutObj: null, // 計時器對象——向后端發(fā)送心跳檢測
        serverTimeoutObj: null, // 計時器對象——等待后端心跳檢測的回復(fù)
        // 心跳檢測重置
        reset: function () {
          clearTimeout(this.timeoutObj);
          clearTimeout(this.serverTimeoutObj);
          return this;
        },
        // 心跳檢測啟動
        start: function () {
          this.timeoutObj && clearTimeout(this.timeoutObj);
          this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
          this.timeoutObj = setTimeout(() => {
            // 這里向后端發(fā)送一個心跳檢測,后端收到后,會返回一個心跳回復(fù)
            this.vueThis.socketObj.send("HeartBeat");
            console.log("發(fā)送心跳檢測");
            this.serverTimeoutObj = setTimeout(() => {
              // 如果超過一定時間還沒重置計時器,說明websocket與后端斷開了
              console.log("未收到心跳檢測回復(fù)");
              // 關(guān)閉WebSocket
              this.vueThis.socketObj.close();
            }, this.timeout);
          }, this.timeout);
        },
      },
      socketReconnectTimer: null, // 計時器對象——重連
      socketReconnectLock: false, // WebSocket重連的鎖
      socketLeaveFlag: false, // 離開標(biāo)記(解決 退出登錄再登錄 時出現(xiàn)的 多次相同推送 問題,出現(xiàn)的本質(zhì)是多次建立了WebSocket連接)
    };
  },
  created() {
    console.log("離開標(biāo)記", this.socketLeaveFlag);
  },
  mounted() {
    // websocket啟動
    this.createWebSocket();
  },
  destroyed() {
    // 離開標(biāo)記
    this.socketLeaveFlag = true;
    // 關(guān)閉WebSocket
    this.socketObj.close();
  },
  methods: {
    // websocket啟動
    createWebSocket() {
      let webSocketLink = "wss://uat.sssyin.cn/ws-reservation"; // webSocket地址
      // console.log(webSocketLink);
      try {
        if ("WebSocket" in window) {
          this.socketObj = new WebSocket(webSocketLink);
        } else if ("MozWebSocket" in window) {
          this.socketObj = new MozWebSocket(webSocketLink);
        }
        // websocket事件綁定
        this.socketEventBind();
      } catch (e) {
        console.log("catch" + e);
        // websocket重連
        this.socketReconnect();
      }
    },
    // websocket事件綁定
    socketEventBind() {
      // 連接成功建立的回調(diào)
      this.socketObj.onopen = this.onopenCallback;
      // 連接發(fā)生錯誤的回調(diào)
      this.socketObj.onerror = this.onerrorCallback;
      // 連接關(guān)閉的回調(diào)
      this.socketObj.onclose = this.oncloseCallback;
      // 向后端發(fā)送數(shù)據(jù)的回調(diào)
      this.socketObj.onsend = this.onsendCallback;
      // 接收到消息的回調(diào)
      this.socketObj.onmessage = this.getMessageCallback;

      //監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時,主動去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會拋異常。
      window.onbeforeunload = () => {
        this.socketObj.close();
      };
    },
    // websocket重連
    socketReconnect() {
      if (this.socketReconnectLock) {
        return;
      }
      this.socketReconnectLock = true;
      this.socketReconnectTimer && clearTimeout(this.socketReconnectTimer);
      this.socketReconnectTimer = setTimeout(() => {
        console.log("WebSocket:重連中...");
        this.socketReconnectLock = false;
        // websocket啟動
        this.createWebSocket();
      }, 4000);
    },
    // 連接成功建立的回調(diào)
    onopenCallback: function (event) {
      console.log("WebSocket:已連接");
      // 心跳檢測重置
      this.heartCheck.reset().start();
    },
    // 連接發(fā)生錯誤的回調(diào)
    onerrorCallback: function (event) {
      console.log("WebSocket:發(fā)生錯誤");
      // websocket重連
      this.socketReconnect();
    },
    // 連接關(guān)閉的回調(diào)
    oncloseCallback: function (event) {
      console.log("WebSocket:已關(guān)閉");
      // 心跳檢測重置
      this.heartCheck.reset();
      if (!this.socketLeaveFlag) {
        // 沒有離開——重連
        // websocket重連
        this.socketReconnect();
      }
    },
    // 向后端發(fā)送數(shù)據(jù)的回調(diào)
    onsendCallback: function () {
      console.log("WebSocket:發(fā)送信息給后端");
    },
    // 接收到消息的回調(diào)
    getMessageCallback: function (msg) {
      // console.log(msg);
      console.log(msg.data);
      if (msg.data.indexOf("HeartBeat") > -1) {
        // 心跳回復(fù)——心跳檢測重置
        // 收到心跳檢測回復(fù)就說明連接正常
        console.log("收到心跳檢測回復(fù)");
        // 心跳檢測重置
        this.heartCheck.reset().start();
      } else {
        // 普通推送——正常處理
        console.log("收到推送消息");
        let data = JSON.parse(msg.data);
        // 相關(guān)處理
        console.log(data);
      }
    },
  },
};
</script>
?著作權(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)容