爲什麼會進行心跳檢測
簡單地說是爲了證明客戶端和服務器還活着。websocket 在使用過程中,如果遭遇網絡問題等,這個時候服務端沒有觸發onclose
事件,這樣會產生多餘的連接,並且服務端會繼續發送消息給客戶端,造成數據丟失。因此需要一種機制來檢測客戶端和服務端是否處於正常連接的狀態,心跳檢測和重連機制就產生了。
如何進行心跳檢測和重連
思路是:
- 每隔一段指定的時間(計時器),向服務器發送一個數據,服務器收到數據後再發送給客戶端,正常情況下客戶端通過
onmessage
事件是能監聽到服務器返回的數據的,說明請求正常。 - 如果再這個指定時間內,客戶端沒有收到服務器端返回的響應消息,就判定連接斷開了,使用
websocket.close
關閉連接。 - 這個關閉連接的動作可以通過
onclose
事件監聽到,因此在 onclose 事件內,我們可以調用reconnect
事件進行重連操作。
具體代碼實現
$(function () {
var path = basePath;
var jspCode = $("#userId").val();
var websocket;
createWebSocket();
/**
* websocket啓動
*/
function createWebSocket() {
try {
if ('WebSocket' in window) {
websocket = new WebSocket((path + "/wsCrm?jspCode=" + jspCode).replace("http", "ws").replace("https", "ws"));
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket(("ws://" + path + "/wsCrm?jspCode=" + jspCode).replace("http", "ws").replace("https", "ws"));
} else {
websocket = new SockJS(path + "/wsCrm/sockJs?jspCode=" + jspCode.replace("http", "ws"));
}
init();
} catch (e) {
console.log('catch' + e);
reconnect();
}
}
function init() {
//連接成功建立的回調方法
websocket.onopen = function (event) {
console.log("WebSocket:已連接");
//心跳檢測重置
heartCheck.reset().start();
};
//接收到消息的回調方法
websocket.onmessage = function (event) {
showNotify(event.data);
console.log("WebSocket:收到一條消息", event.data);
heartCheck.reset().start();
};
//連接發生錯誤的回調方法
websocket.onerror = function (event) {
console.log("WebSocket:發生錯誤");
reconnect();
};
//連接關閉的回調方法
websocket.onclose = function (event) {
console.log("WebSocket:已關閉");
heartCheck.reset();//心跳檢測
reconnect();
};
//監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。
window.onbeforeunload = function () {
websocket.close();
};
//關閉連接
function closeWebSocket() {
websocket.close();
}
//發送消息
function send(message) {
websocket.send(message);
}
}
//避免重複連接
var lockReconnect = false, tt;
/**
* websocket重連
*/
function reconnect() {
if (lockReconnect) {
return;
}
lockReconnect = true;
tt && clearTimeout(tt);
tt = setTimeout(function () {
console.log('重連中...');
lockReconnect = false;
createWebSocket();
}, 4000);
}
/**
* websocket心跳檢測
*/
var heartCheck = {
timeout: 5000,
timeoutObj: null,
serverTimeoutObj: null,
reset: function () {
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function () {
var self = this;
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
this.timeoutObj = setTimeout(function () {
//這裏發送一個心跳,後端收到後,返回一個心跳消息,
//onmessage拿到返回的心跳就說明連接正常
websocket.send("HeartBeat");
console.log('ping');
self.serverTimeoutObj = setTimeout(function () { // 如果超過一定時間還沒重置,說明後端主動斷開了
console.log('關閉服務');
websocket.close();//如果onclose會執行reconnect,我們執行 websocket.close()就行了.如果直接執行 reconnect 會觸發onclose導致重連兩次
}, self.timeout)
}, this.timeout)
}
};
});