阅读本文章前请先了解WebSocket
场景
WebSocket在连接关闭的情况下会触发onclose事件,在链接异常的情况下会触发onerror事件。而在弱网条件下,onclose事件触发的灵敏度却不高,往往已经断网很久了才触发onclose事件,前端又去进行重连操作,对实时界面的展示不友好。所以,本文将介绍心跳重连机制来改善这一现象。
解决方案
心跳重连机制:前端在WS连接成功的情况下,开始执行心跳函数,首先向服务器端发送‘ping’信息,服务器内若收到信息则会返回’pong’信息。在一定时间内,前端收到服务器返回的信息,则表示此连接是正常的,便重置心跳函数;若前端在一定时间内没有收到心跳函数,则表明没有连接成功,此时前端关闭ws,再执行重连操作。
代码块:
import { mapActions, mapState } from 'vuex';
export default {
name: 'Websocket',
data() {
return {
// 是否正在重连
lockReconnect: false,
socket: null,
reconnectTimeout: null,
timeout: 10 * 1000,
timer: null,
serverTimer: null
};
},
computed: {
...mapState(['userInfo']),
wsuri() {
return `${process.env.VUE_APP_WEBSOCKET_URI}${this.userInfo.tenantId};${this.userInfo.userId}`;
}
},
async mounted() {
await this.getUserInfo();
this.initWebSocket();
},
destroyed() {
this.socket.close();
},
methods: {
...mapActions(['getUserInfo']),
start(ws) {
this.reset();
this.timer = setTimeout(() => {
// console.log('发送心跳,后端收到后,返回一个心跳消息')
// onmessage拿到返回的心跳就说明连接正常
ws.send('ping');
this.serverTimer = setTimeout(() => {
// 如果超过一定时间还没响应(响应后触发重置),说明后端断开了
ws.close();
}, this.timeout);
}, this.timeout);
},
reset() {
this.serverTimer && clearTimeout(this.serverTimer);
this.timer && clearTimeout(this.timer);
},
reconnect() {
console.log('尝试重连');
if (this.lockReconnect) {
return;
}
this.lockReconnect = true;
this.reconnectTimeout && clearTimeout(this.reconnectTimeout);
this.reconnectTimeout = setTimeout(() => {
this.initWebSocket();
this.lockReconnect = false;
}, 4 * 1000);
},
initWebSocket() {
try {
if ('WebSocket' in window) {
this.socket = new WebSocket(this.wsuri);
} else {
console.log('您的浏览器不支持websocket');
}
this.socket.onopen = this.websocketOnOpen;
this.socket.onerror = this.websocketOnError;
this.socket.onmessage = this.websocketOnMessage;
this.socket.onclose = this.websocketClose;
} catch (e) {
this.reconnect();
}
},
websocketOnOpen() {
console.log('WebSocket连接成功', this.socket.readyState);
this.start(this.socket);
this.websocketSend();
},
websocketOnError(e) {
console.log('WebSocket连接发生错误', e);
this.reconnect();
},
websocketOnMessage(e) {
if (e.data === 'pong') {
// 消息获取成功,重置心跳
this.start(this.socket);
}
},
websocketClose(e) {
console.log('connection closed (' + e.code + ')');
this.reconnect();
},
websocketSend() {
this.socket.send('ping');
}
}
};
|