vue接入websocket
首先就是網(wǎng)上的寫法有很多但是 都是需要創(chuàng)建一個對象進行相關的狀態(tài)回調(diào),有的是需要創(chuàng)建一個初始化方法進行相關的狀態(tài)回調(diào),然后看的我就一句話 都挺好的,反正就是需要你去創(chuàng)建對象接收發(fā)送消息,然后我就在這寫一個全局的使用的,因為我覺得大部分就是作為消息推送來用所以全局來用蠻好的。
websocket是什么:
首先是是基于TCP的 全雙工 通信的協(xié)議 然后就是websoket是通過客戶端向服務器建立連接,保持客戶端和服務器端雙向的通信的過程。相互收發(fā)消息
websocket的使用相關實例狀態(tài):
1>readyState屬性返回實例對象的當前狀態(tài)。共四種:
CONNECTING:值為0,表示正在連接。
OPEN:值為1,表示連接成功,可以通信了。
CLOSING:值為2,表示連接正在關閉。
CLOSED:值為3,表示連接已經(jīng)關閉,或者打開連接失敗。
2> onopen: 實例對象的onpen屬性,用于指定連接成功后的回調(diào)函數(shù)。
3>onclose: 實例對象的onclose屬性,用于指定連接關閉后的回調(diào)函數(shù)。
4>onmessage: 實例對象的onmessage屬性,用于指定收到服務器 數(shù)據(jù)后的回調(diào)函數(shù)。
5>send:實例對象的send()方法用于向服務器發(fā)送數(shù)據(jù)
具體使用:
1>首先創(chuàng)建一個全局文件: 在main.js 里面進行引入
// global.js 文件
export default {
ws: {},
setWs: function(newWs) {
this.ws = newWs
}
}
// main.js 文件
import global from './xx/global.js'
Vue.prototype.global = global
2> 在APP.vue 里面進行初始化 (回調(diào)有多個狀態(tài) 但是只寫了連接成功和失敗的方法)
//app.vue
oncerate(){
//初始化方法
this.localSocket
}
methods(){
//app.vue
localSocket() {
let that = this;
if ("WebSocket" in window) {
// console.log("您的瀏覽器支持 WebSocket!");
// location.host
that.ws = new WebSocket("ws://"+ 'ceshidizhi');
that.global.setWs(that.ws);
that.ws.onopen = function () {
console.log('websocket連接成功');
};
that.ws.onclose = function () {
// 關閉 websocket
console.log("連接已關閉...");
//斷線重新連接
setTimeout(() => {
that.localSocket();
}, 2000);
};
} else {
// 瀏覽器不支持 WebSocket
console.log("您的瀏覽器不支持 WebSocket!");
this.openNotificationWithIcon('error', '瀏覽器', '您的瀏覽器不支持顯示消息請更換', 1,1)
}
},
}
3>然后就可以在其他頁面進行數(shù)據(jù)交互( 看代碼就能看出來 使用全局的對象進行數(shù)據(jù)獲取發(fā)送)
//pageA.vue
// 發(fā)送和接收消息
handdleMsg(msg) {
let that = this;
console.log(that.global.ws);
if (that.global.ws && that.global.ws.readyState == 1) {
console.log("發(fā)送信息", msg);
that.global.ws.send(msg);
}
that.global.ws.onmessage = function(res) {
console.log("收到服務器內(nèi)容", res);
};
}
展示效果:我沒有截圖 就是連接成功后console里面會輸出值的 跑起來看看就知道了
注意:
在使用的時候,初始化不一定要放在 APP.vue里面 就像我需要在登錄成功之后拿到一個值,使用這個值去拼接地址,所以我就只能登錄后在進行連接,我就省了個事情,直接放在了頂部的組件里面。
長連接 在長時間不發(fā)送消息的時候,會自動斷開。原因是運維那塊使用了nginx服務,會配置一個時間段, 在這個時間里,如果一直滅有數(shù)據(jù)的傳輸,連接就會在這個時間之后自動關閉。因為我們無法控制用戶什么時候去觸發(fā)websocket消息的推送。所以下邊
心跳包機制:
//在onopen開始之后直接進行f方法調(diào)用 數(shù)據(jù)數(shù)據(jù)發(fā)送
start() { // 發(fā)送心跳
clearInterval(this.timeoutObj)
this.timeoutObj = setInterval(() => {
let that = this;
let date = new Date()
if (that.global.ws && that.global.ws.readyState == 1) {
console.log("發(fā)送信息", msg);
that.global.ws.send(`發(fā)送心跳給后端${date}`);
}
}, 2 * 60 * 1000)
}
代碼
// 創(chuàng)建websocket連接
createWebSocket(){
let that = this;
that.webSocet = null;
that.webSocet= new WebSocket(process.env.VUE_APP_SOCKET_URL);
// console.log('that.webSocet',that.webSocet);
if(that.webSocet.readyState == 0 && !that.timeoutnum){
that.timer = setInterval(() => {
if(that.timer_num < 3 && that.webSocet.readyState == 0 ){
that.timer_num++;
}else{
clearInterval(that.timer);
that.timer = null;
that.timer_num = 0;
// 只要不成功就連接
if(that.webSocet.readyState != 1){
that.reconnect();
}
}
}, 1000);
}
//鏈接成功時
that.webSocet.onopen = function(){
//開啟心跳
that.start();
}
//收到消息時
that.webSocet.onmessage = (msgInfo) => {
// console.log('接收到的消息',msgInfo);
that.UP_WEBSOCKETINFO({data:msgInfo.data,timer:msgInfo.timeStamp});
//收到服務器信息,心跳重置
that.reset();
}
//連接錯誤
that.webSocet.onerror = function(){
console.log("WebSocket連接發(fā)生錯誤");
//重連
that.reconnect();
};
// 監(jiān)聽組件的銷毀
that.$once('hook:beforeDestroy', () => {
if(that.webSocet.close){
that.webSocet.close();
that.webSocet.onclose = () =>{
console.log('web socket 鏈接已關閉');
};
}
})
},
reconnect() {//重新連接
let that = this;
if(that.webSocet && that.webSocet.readyState == 1){
clearInterval(that.timeoutnum);
that.timeoutnum = null;
that.timeNum = 0;
return;
}
if(!that.timeoutnum) {
that.timeoutnum = setInterval(function () {
if(that.webSocet && that.webSocet.readyState == 1){
clearInterval(that.timeoutnum);
that.timeoutnum = null;
that.timeNum = 0;
return;
}
//新連接
that.createWebSocket();
that.timeNum++;
if(that.timeNum >= 3){
clearInterval(that.timeoutnum);
that.timeoutnum = null;
that.timeNum = 0;
}
},1000);
};
},
reset(){//重置心跳
//清除時間
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
//重啟心跳
this.start();
},
start(){//開啟心跳
let that = this;
that.timeoutObj && clearTimeout(that.timeoutObj);
that.serverTimeoutObj && clearTimeout(that.serverTimeoutObj);
that.timeoutObj = setTimeout(function(){
//這里發(fā)送一個心跳,后端收到后,返回一個心跳消息,
if (that.webSocet && that.webSocet.readyState == 1) {//如果連接正常
that.webSocet.send(
that.userInfo.userId + '-' +
that.userInfo.userName + '-' +
that.userInfo.token
);
}else{//否則重連
that.reconnect();
}
}, that.timeout)
},
...mapMutations('userInfo',{
UP_WEBSOCKETINFO:'UP_WEBSOCKETINFO'
})
[websocket關于禁止一個賬號多窗口鏈接的問題]
通過websocket的session.getSessionId()與oldSession.getSessionId()來equals判斷是否是新窗口。 如果不同不讓鏈接。
問題1.雖然新來的鏈接連不上,但是如果原窗口的鏈接斷線重連也會認為是新socket,也會被禁止鏈接。
解決方法: 原窗口鏈接時,原客戶端窗口先發(fā)關閉請求, 然后再連即可連上。
問題2. 如果上面原客戶端窗口關閉請求服務端沒有收到怎么辦? (網(wǎng)絡情況很復雜)
可以在onError和onClose中獲取到指定的oldSession,判斷isOpen(), 如果為false則說明已為僵尸鏈接,移除它即可。