一、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>