vue uni-app websocket断开重连、心跳机制
由于web/app有时候会出现网络不稳定websocket会自动断开连接导致消息推送不了的情况,所以查阅资料后发现了一个心跳机制,也就是客户端间隔一段时间就向服务器发送一条消息,如果服务器收到消息就回复一条信息过来,如果一定时间内没有回复,则表示已经与服务器断开连接了,这个时候就需要进行重连。
由于web/app有时候会出现网络不稳定websocket会自动断开连接导致消息推送不了的情况,所以查阅资料后发现了一个心跳机制,也就是客户端间隔一段时间就向服务器发送一条消息,如果服务器收到消息就回复一条信息过来,如果一定时间内没有回复,则表示已经与服务器断开连接了,这个时候就需要进行重连。
首先在vue里使用:
var lockReconnect = false; //避免ws重复连接
var ws = null; // 判断当前浏览器是否支持WebSocket
var wsUrl = serverConfig.socketUrl;
createWebSocket(wsUrl); //连接ws
function createWebSocket(url) {
try{
if('WebSocket' in window){
ws = new WebSocket(url);
}
initEventHandle();
}catch(e){
reconnect(url);
console.log(e);
}
}
function initEventHandle() {
ws.onclose = function () {
reconnect(wsUrl);
console.log("llws连接关闭!"+new Date().toLocaleString());
};
ws.onerror = function () {
reconnect(wsUrl);
console.log("llws连接错误!");
};
ws.onopen = function () {
heartCheck.reset().start(); //心跳检测重置
console.log("llws连接成功!"+new Date().toLocaleString());
};
ws.onmessage = function (event) { //如果获取到消息,心跳检测重置
heartCheck.reset().start(); //拿到任何消息都说明当前连接是正常的
console.log("llws收到消息啦:" +event.data);
if(event.data!='pong'){
let data = JSON.parse(event.data);
}
};
}
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
ws.close();
}
function reconnect(url) {
if(lockReconnect) return;
lockReconnect = true;
setTimeout(function () { //没连接上会一直重连,设置延迟避免请求过多
createWebSocket(url);
lockReconnect = false;
}, 2000);
}
//心跳检测
var heartCheck = {
timeout: 600000, //10分钟发一次心跳
timeoutObj: null,
serverTimeoutObj: null,
reset: function(){
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function(){
var self = this;
this.timeoutObj = setTimeout(function(){
//这里发送一个心跳,后端收到后,返回一个心跳消息,
//onmessage拿到返回的心跳就说明连接正常
ws.send("ping");
console.log("ping!")
self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
ws.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
}, self.timeout)
}, this.timeout)
}
}
在uni-app中使用:两个差别不大,只有new websocket的方法不一样:
wsObj = uni.connectSocket({
url: url,
success: () => {
console.log('WebSocket 连接成功');
},
fail: (err) => {
console.log("uni connect socket err: ", err);
}
});
遇到的坑一:
不知道大家有没有注意每次重连的时候,我们都是重新new一个websocket,下面是正常新建websocket的对象,readyState为1,但是由于我的需求是要在不同的layout里使用websocket,所以没有每次new一遍,这样会导致页面刷新并且退出登录,所以我做了一个判断,如果有websocket并且readState不为3就不用再new一次,并且见下面代码,至于为什么会用到readState,等下来说
function createWebSocket (enterWsHost) {
wsHost = enterWsHost
console.log('在连接中吗',wsHost)
try {
if ('WebSocket' in window) {
if (ws && ws.readyState !== 3) {
console.log('用之前的ws')
return ws
} else {
console.log('重新创建ws')
ws = new WebSocket(wsHost)
}
initEvent()
}
} catch (error) {
console.log('失败')
// 重连
reconnect(wsHost)
}
}
为什么必要要判断readState呢,首先来看看它的所有状态码,它表示当前连接的状态:3表示连接已经关闭或者没有连接成功,所以当有这种情况只有重新new一次。
0 (WebSocket.CONNECTING)
正在链接中
1 (WebSocket.OPEN)
已经链接并且可以通讯
2 (WebSocket.CLOSING)
连接正在关闭
3 (WebSocket.CLOSED)
连接已关闭或者没有链接成功
遇到的坑二:
websocket的onopen / onmessage / onerror / onclose四个属性会有一个回调函数,之前用的时候完全没有注意先后顺序,直接随便写的,但是发现会出现收不到服务器的消息情况,后来检查了很久才发现顺序错了。
WebSocket.onopen
属性定义一个事件处理程序,当WebSocket
的连接状态readyState
变为1
时调用;这意味着当前连接已经准备好发送和接受数据。
WebSocket.onmessage
属性是一个当收到来自服务器的消息时被调用。
这两个调用的顺序,必须是onopen在前面,onmessage在后面,不然就会出现接收不到消息的情况
更多推荐
所有评论(0)