WebSocket是前后端交互的长连接,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。项目中,我们经常会使用WebSocket和服务器建立持久的连接。
但是前后端也会因为某些不明因素链接断开(我就是因为经常断网),导致前后端都没有反馈的情况
所以为了保持链接的稳定性和持续性,心跳重连就必须整上去了,也顺便记录一下实现心跳重连的流程
在使用WebSocket的时候,如果网络突然断开,WebSocketd是不会触发任何事件的,所以前端程序无法得知当前链接是否断开。但是这个时候使用WebSocket.send方法的时候,浏览器会发现消息发不出去,隔一段时间之后(貌似每个浏览器隔的时间不相同),会触发onclose函数。利用这点,我们可以在send不出消息并触发onclose之后,进行重连
当然后端也可能出现异常,他收到了这个消息,但是没响应回来,前端也收不到通知,差不多就是你给一个人打电话,那niao人不说话的情况,问题你还不知道他在不在。所以这种情况我们要隔段时间send一次,假如超过一定时间没收到回应,那就默认是异常了,就触发重连。
WebSocket的各个绑定事件:
let ws = new WebSocket(url);ws.onopen = function () { //something}ws.onmessage = function (event) { //something}ws.onclose = function () { //something}ws.onerror = function () { //something}
好了,按照这个思路,开始:
// 心跳检测let heartCheck = { timeout: 60000, // 超时时间 timer: null, serverTimer: null, reset: function(){ clearTimeout(this.timer); this.start(); }, start: function(){ this.timer = setTimeout(function(){ ws.send('connectTest'); }, this.timeout) }}
定义了一个心跳检测,当open的时候,执行heartCheck.start()方法,然后onmessage收到信息之后调用heartCheck.reset()方法重置,这样每次onmessage就触发send,达到循环发送的效果。
当send失败的时候,隔一段时间会自动触发onclose,所以要在onclose的时候调用重连
ws.onclose = function () { console.log('onclose'); reconnect();}
重连的时候需要注意防止重复连接,还要设置延迟,避免请求太频繁
let lockReconnect = false;/** * @method reconnect ws重新连接 * @description lockReconnect防止重复连接,时间戳避免在失败时候会频繁建立ws连接 */ function reconnect() { if(lockReconnect) return; lockReconnect = true; //没连接上会一直重连,设置延迟避免请求过多 setTimeout(function () { createWebSocket(); // 创建webSocket连接的方法 lockReconnect = false; }, 2000);}
如此上面流程就解决了如断网send不出消息的时候重连的效果,测试的时候可以手动断网测,亲测有效
好了,现在假设后端异常,没数据返回,onmessage就进不去,得另外想办法。所以在每次send的时候的setTimeout内再加一个setTimeout,就是,如果里面这个setTimeout执行了,那就不等了,我觉得他是挂了,重连。
// 心跳检测let heartCheck = { timeout: 60000, // 超时时间 timer: null, serverTimer: null, reset: function(){ clearTimeout(this.timer); clearTimeout(this.serverTimer); this.start(); }, start: function(){ let ts = this; this.timer = setTimeout(function(){ ws.send('connectTest'); // 超出时间内未响应就主动关闭链接,关闭链接会触发重连 ts.serverTimer = setTimeout(function(){ ws.onclose(); }, ts.timeout) }, this.timeout) }}
如果onmessage收到消息,执行了reset会清空所有的timer,重新计时, nice~~~。
这样就完成了websocket的心跳重连,归纳一下代码:
let lockReconnect = false; //避免重复连接let ws;// 心跳检测let heartCheck = { timeout: 60000, timer: null, serverTimer: null, reset: function(){ clearTimeout(this.timer); clearTimeout(this.serverTimer); this.start(); }, start: function(){ let ts = this; this.timer = setTimeout(function(){ ws.send('connectTest'); ts.serverTimer = setTimeout(function(){ ws.onclose(); }, ts.timeout) }, this.timeout) }}// 创建WebSocket链接function createWebSocket () { if ("WebSocket" in window) { if (!url) return ws = new WebSocket(url); // WebSocket事件方法 initEventHandle(); } else { console.log('您的浏览器不支持websocket') }}/** * @method initEventHandle 初始化ws各个事件的方法 */function initEventHandle (url) { ws.onopen = function () { heartCheck.start(); console.log('链接成功:', url); } //获得消息事件 ws.onmessage = function(data, state) { // 收到消息的时候重置倒计时 heartCheck.reset(); //something } ws.onerror = function() { message('error', 'WebSocket连接错误!正在重连'); reconnect(); } ws.onclose = function () { console.log('onclose'); reconnect(); }}/** * @method reconnect ws重新连接 * @description lockReconnect防止重复连接,时间戳避免在失败时候会频繁建立ws连接 */function reconnect() { if(lockReconnect) return; lockReconnect = true; //没连接上会一直重连,设置延迟避免请求过多 setTimeout(function () { createWebSocket(); lockReconnect = false; }, 2000);}