一、 websocket 是什么?
websocket 是一種網(wǎng)絡(luò)通信協(xié)議,與 http 語義一樣轨淌,但功能不一樣
http 也是一種網(wǎng)絡(luò)通信協(xié)議迂烁,為什么不用 http 而用 websocket ?
二、websocket 與 http 有什么區(qū)別猿诸?
websocket 通信可由服務(wù)器發(fā)起婚被,也可以由客戶端發(fā)起∈崴洌可以實(shí)現(xiàn)客戶端與服務(wù)端長連接
http 通信只能由客戶端發(fā)起址芯。
三、WebSocket 觸發(fā)事件
以下是 WebSocket 對象的相關(guān)事件窜觉。
四谷炸、WebSocket 方法
假定我們使用了以上代碼創(chuàng)建了 Socket 對象:this.Socket.close()/this.Socket.send()
WebSocket 組件封裝(包含健康檢查和心跳機(jī)制)
<template></template>
<script>
import { mapGetters } from "vuex";
export default {
data () {
return {
// ws
maxReconnect: 3, // 最大重連次數(shù),-1代表無限重連
reconnectTime: 0, // 重連嘗試次數(shù)
socket: "",
uri: "",
lockReconnect: false,
timer: null,
heartbeat: null,
heartbeatTimeOut: null,
};
},
computed: {
...mapGetters(["userInfo"]),
},
beforeDestroy () {
this.destroyedWs();
},
methods: {
destroyedWs () {
console.log("ws銷毀");
// 關(guān)閉使用close方法關(guān)閉socket
if (this.socket) {
this.socket.close();
}
this.socket = null;
// 清除定時器
this.timer = null;
clearInterval(this.timer);
clearTimeout(this.heartbeat);
this.heartbeat = null;
clearTimeout(this.heartbeatTimeOut);
this.heartbeatTimeOut = null;
},
//初始化方法
init () {
this.initWebSocket();
},
// 初始化WebSocket
initWebSocket () {
if (typeof WebSocket === "undefined") {
alert("您的瀏覽器不支持socket");
} else {
const uri =
"ws://" +
"192.168.0.114:8686" +
"/mqtt-print/imserver/" +
this.userInfo.userId;
// 實(shí)例化socket
this.socket = new WebSocket(uri);
// 監(jiān)聽socket連接
this.socket.onopen = this.open;
// 監(jiān)聽socket錯誤信息
this.socket.onerror = this.error;
// 監(jiān)聽socket消息
this.socket.onmessage = this.getMessage;
// 連接關(guān)閉
this.socket.onclose = this.close;
}
},
open: function () {
console.log("socket連接成功");
//開啟心跳
this.startHeartbeat();
},
error: function () {
console.log("連接錯誤");
//重連
this.reconnect();
},
getMessage: function (msg) {
const text = msg.data;
//收到服務(wù)器信息,心跳重置并發(fā)送
this.startHeartbeat();
if (text.indexOf("ping") > 0) {
return;
}
this.$emit("getMessage", text);
},
send: function (params) {
this.socket.send(params);
},
close: function () {
console.log("socket已經(jīng)關(guān)閉");
},
/**
* 重新連接(無限重連)
*/
reconnect () {
if (this.socket.readyState === 1) {
// 如果狀態(tài)等于1代表 websocket連接正常
return;
}
if (
this.lockReconnect ||
(this.maxReconnect !== -1 && this.reconnectTime >= this.maxReconnect)
) {
return;
}
// 讓重連鎖變?yōu)閠rue禀挫,阻止進(jìn)入下一個循環(huán)
this.lockReconnect = true;
setTimeout(() => {
this.reconnectTime++;
console.log("嘗試重連");
// 建立新連接
this.initWebSocket();
this.lockReconnect = false;
}, 5000);
},
/**
* 開啟心跳
*/
startHeartbeat () {
const webSocket = this.socket;
// 清空定時器
clearTimeout(this.heartbeat);
this.heartbeat = null;
clearTimeout(this.heartbeatTimeOut);
this.heartbeatTimeOut = null;
// 延時發(fā)送下一次心跳
// console.log("心跳開啟");
this.heartbeat = setTimeout(() => {
// 如果連接正常
// console.log("連接狀態(tài)", webSocket.readyState);
if (webSocket.readyState === 1) {
//這里發(fā)送一個心跳旬陡,后端收到后,返回一個心跳消息语婴,
let params = JSON.stringify({
type: "ping",
toUserId: this.userInfo.userId,
});
webSocket.send(params);
// 心跳發(fā)送后描孟,如果服務(wù)器超時未響應(yīng)則斷開,如果響應(yīng)了會被重置心跳定時器
this.heartbeatTimeOut = setTimeout(() => {
webSocket.close();
// 響應(yīng)超時時間
}, 10 * 1000);
} else {
// 否則重連
this.reconnect();
}
// 心跳間隔時間是30s
}, 30 * 1000);
},
},
};
</script>