最近被问到一个项目中比较常见的问题,因为之前自己只是用过,但并未真正了解具体是怎么实现的,所以今天抽时间整理了下,避免下次再掉坑中。。
一般toB的项目中,如果有实时通信的需求,目前较为广泛的都会采用websocket来实现客户端与服务端的双向通信,其实主要原理是客户端定时向服务端发送消息,如果在规定时间内,收到服务端推送回的消息,则说明通信正常,否则就挂掉了,及时关闭连接;
今天简单封装了下,websocket中的心跳重连,主要代码如下:
class HeartSocket { constructor(options) { this.url = options.url; //请求路径 this.timeout = options.timeout;//心跳超时时间 毫秒 this.isHeart = options.isHeart;//是否开启心跳 this.isReconnection = options.isReconnection; //是否断开重连 this.ws = null; ///WebSocket的引用 this.status = null;//记录状态 this.lockReconnect = false,//避免重复连接 this.timeoutObj = null;//模拟延时器1 this.serverTimeoutObj = null;//模拟延时器2 } reConnection() { if (this.lockReconnect) return; this.lockReconnect = true; //判断当前浏览器是否支持WebSocket if (‘WebSocket‘ in window) { this.ws = new WebSocket(this.url); } else { alert(‘Not support websocket‘) } //打开连接 this.ws.onopen = (e) => { this.status = ‘open‘; console.log(‘socket连接成功‘, e) if (this.isHeart) this.heartCheck(); } //消息交互 this.ws.onmessage = (e) => { console.log(‘后台接收到前台传值,还有心跳...‘); //心跳检测重置 this.heartCheck(); } //关闭连接 this.ws.onclose = (e) => { console.log(‘关闭连接‘, e); this.closeSocket(e); } //报错 this.ws.onerror = (e) => { console.log(‘error‘, e); this.closeSocket(e); } } resetHeart() { this.timeoutObj && clearTimeout(this.timeoutObj); this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj); } heartCheck() { console.log(‘开始测试心跳‘); this.timeoutObj = setTimeout(() => { //这里发送一个心跳,后端收到后,返回一个心跳消息, console.log(‘发送消息,测试后台是否运行中...‘); //任意发一个消息过去,后台接收,如果在onmessage收到消息,说明后台没有挂掉,有心跳 this.ws.send("666"); this.serverTimeoutObj = setTimeout(() => { console.log("后台挂掉,没有心跳了...."); console.log("打印websocket的地址:" + this.url); this.ws.close(); // createWebSocket(); }, this.timeout); this.lockReconnect = false; }, this.timeout); } closeSocket(e) { this.resetHeart(); if (this.status !== ‘close‘) { console.log(‘断开,重连‘, e) if (this.isReconnection) { console.log("正在重连,当前时间" + new Date()) //重连 this.reConnection(); } } else { //手动关闭 console.log(‘手动关闭‘, e) } } close() { this.status = ‘close‘; this.resetHeart(); return this.ws.close(); } sendMsg(data) { let msg = JSON.stringify(data); return this.ws.send(msg) } }
调用如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>websocket心跳重连</title> </head> <body> <div> <input type="text" placeholder="请输入路径" value="ws://172.16.253.166:48081/websocket" id="url"> <button onclick="concat()"> concat </button> <button onclick="closeWebSocket()"> close </button> </div> <script src="./index.js"></script> <script> let url = document.getElementById(‘url‘).value; const ws = new HeartSocket({ url: url, isHeart: true, //是否心跳 timeout: 10000,// 心跳间隔时间 isReconnection: true, //是否断开后自动重连 }) function concat() { //判断客户端是否联网 // if (navigator.onLine) { // console.log(‘网络已连接‘); // } else { // console.log(‘已断网‘); // } ws.reConnection(); } // 发送消息 //ws.sendMsg(message); //关闭连接 function closeWebSocket() { if (ws) ws.close(); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function () { ws.close(); } </script> </body> </html>
如有问题,还请及时指正,蟹蟹~