通过以上设计思路和技巧,我们实现了一个可靠的WebSocket连接和重连机制的工厂类。这个工厂类简化了WebSocket连接的管理和操作,提供了方便的接口和灵活的配置选项,使得开发人员能够更轻松地实现实时通信功能,并增加了连接的稳定性和可靠性。
export interface WebSocketParam { ip: string; onmessage: (msg: any) => void; closeable: boolean; } type TimerInsert = { mountedTimerRelative?: (msg: any) => void; }; // websocket客户端工厂 export default class WSClientFactory { // websocket实例对象 wsInstance: WebSocket & TimerInsert = null; // 构造参数 param: WebSocketParam; // 重联锁 lockReconnect = false; // 心跳间隔器的句柄 checkTimer: NodeJS.Timer = null; // 表明此websocket是否是可以关闭的(如果不可以关闭,则断开重连之后会自动重新连接) closeable = false; // 是否是第一次连接 isFirstConnect = true; // 消息处理函数 onmessage = Function(); constructor(param: WebSocketParam) { const { closeable = false, onmessage = Function() } = param; this.param = param; this.closeable = closeable; this.onmessage = onmessage; } private connectCallback() { // 在通道打开的时候就设置一个间隔器用来做心跳检查 this.checkTimer = setInterval(() => { if (this.wsInstance) { try { this.wsInstance.send("alive"); } catch (e) { this.reconnect(); } } }, 15000); // 分两种情况:首次和非首次连接到后端;两种情况下连接之后像后端发送不同的消息 if (!this.isFirstConnect) { this.wsInstance.send( JSON.stringify({}) ); } else { this.wsInstance.send(JSON.stringify({})); } // 修改首次连接的token this.isFirstConnect = false; } // ws实例(wsInstance)发生错误时的回调函数,功能为重新连接 private errorCallback(e) { this.reconnect(); } // ws实例关闭事件的回调函数,功能为检测此ws实例能否被关闭,如果不允许关闭则重新连接 private closeCallback() { if (!this.closeable) this.reconnect(); } // 堆代码 duidaima.com // 建立连接的方法(如果不进行封装,则ws连接会在new WebSocket()也就是WebSocket实例化的时候连接上,这一点非常的不具有语义性,封装之后就好多了) public connect() { if (!this.wsInstance) { // 获得WebSocket的实例化对象 this.wsInstance = new WebSocket( `ws://${this.param.ip}/ws?token=${localStorage.getItem('token')}` // 一般建立ws都要用凭证的,而凭证就存放在localStorage里面 ); // 设置ws实例对象的onopen回调参数 this.wsInstance.onopen = (e) => { this.connectCallback(); }; // 设置ws实例对象的onerror回调参数 this.wsInstance.onerror = (e) => { this.errorCallback(e); }; // 设置ws实例对象的onopen回调参数 this.wsInstance.onmessage = (e) => { this.param.onmessage(e.data); }; // 设置ws实例对象的onclose回调参数 this.wsInstance.onclose = (e) => { this.closeCallback(); }; } } // 重新连接的方法 private reconnect() { // 如果重新连接功能被禁止,则无需再执行后面的逻辑; // 锁的目的是为了保证reconnect方法不会被出发多次 if (this.lockReconnect) return; this.lockReconnect = true; // ws实例请求连接之后,立即释放重连锁,可勉强是可以的,因为重连方法的入口只有这里一处,这里使用的是一个定时器,所以下一次重连在五秒 setTimeout(() => { this.destroy(); this.connect(); this.lockReconnect = false; }, 5000); } // 暴露一个发送信息的接口 public sendMsg(msg: any) { this.wsInstance?.send(msg); } // 向外暴露一个取消此封装实体的方法:1. 消除心跳间隔器; 2. 关闭ws实例连接之后删除ws实例对象 public destroy() { // 处理定时器 clearInterval(this.checkTimer); this.checkTimer = null; // 处理ws实例 this.closeable = true; this.wsInstance.close(); this.wsInstance = null; // 重置其它参数 this.lockReconnect = false; this.isFirstConnect = true; // 没有处理this.params这是因为,params可以在合适的时机继续使用:const newWS = new WSClientFactory(oldWS.params); } }三. 服务端代码
const WebSocket = require('ws'); const wss = new WebSocket.Server({ noServer: true }); wss.on('connection', (ws) => { console.log('WebSocket connection established.'); // 发送确认连接的消息给客户端 ws.send('Connection established.'); ws.on('message', (message) => { console.log('Received message:', message); }); ws.on('close', () => { console.log('WebSocket connection closed.'); }); }); const server = require('http').createServer(); server.on('upgrade', (request, socket, head) => { wss.handleUpgrade(request, socket, head, (ws) => { wss.emit('connection', ws, request); }); }); server.listen(8080, '127.0.0.1', () => { console.log('WebSocket server listening on ws://127.0.0.1:8080'); });四. 测试用例
const param = { ip: "127.0.0.1:8080", closeable: false, onmessage: function (msg) { console.log(msg); } }; const ws = new WSClientFactory(param); console.log('ws: ', ws); // ws: WSClientFactory {wsInstance: null, lockReconnect: false, checkTimer: null, closeable: false, isFirstConnect: true, …} ws.connect(); // Connection established. ws.sendMsg('1123213'); ws.destroy(); const ws2 = new WSClientFactory(ws.param); ws2.connect(); // Connection established.五 总结: