前端开发websocket的过程是页面初始化后创建了websocket长连接,然后心跳检测,在意外关闭后重重连websocket,离开页面后就对websocket进行销毁,这是很正常的逻辑。
然后在开发过程发现一个问题,离开页面后定时器依然在检测心跳,而且离开后会关闭一次然后被重新连接了,这会导致后台推送数据的时候多次重复出现,甚至在多个不同聊天人之间也出现原来的用户聊天推送(在其它端口推送时,后台根据用户id推送)。
之前前端同事对接出现这个问题就没解决,后台是没问题的,前端同事也不想多干活,反正就是不愿意处理。
现在我自己开发自己的项目,自己图手写了个聊天客服,如下图一样。然后发现了这个问题是普遍存在的,而且就是前端未能清理socket的问题,导致消息混乱。
一开始页面的清理是这样的
beforeDestroy() { console.log('页面销毁') this.closeWebSocket(); }, onUnload() { console.log('页面卸载') this.closeWebSocket(); }, //关闭清理的方法 closeWebSocket() { if (this.websocket) { this.websocket.close(); this.websocket = null; } if (this.heartbeatInterval) { // 清除心跳检测定时器 clearInterval(this.heartbeatInterval); this.heartbeatInterval = null; } }, //websocket关闭监听函数 // 处理 WebSocket 关闭 handleWebSocketClose() { if (this.reconnectTimes < this.maxReconnectTimes) { setTimeout(() => { this.reconnectTimes++ this.connectWebSocket() }, 3000) } else { this.isServiceOnline = false uni.showToast({ title: '客服暂时离线,请留言', icon: 'none' }) } },
知道问题是websocket未清理彻底的问题就好办了,解决起来也简单,就是在卸载页面的时候价加上状态,比如leave=true,然后这个状态成立的时候不允许重连即可。根源的问题是重连发生的。修改如下
beforeDestroy() { console.log('页面销毁') this.leave = true this.closeWebSocket(); }, onUnload() { console.log('页面卸载') this.leave = true this.closeWebSocket(); }, // 处理 WebSocket 关闭 handleWebSocketClose() { if (this.leave){ console.log('页面已离开,不再重连'); return ; } if (this.reconnectTimes < this.maxReconnectTimes) { setTimeout(() => { this.reconnectTimes++ this.connectWebSocket() }, 3000) } else { this.isServiceOnline = false uni.showToast({ title: '客服暂时离线,请留言', icon: 'none' }) } },
就是在卸载和销毁页面的时候做状态,防止被重连了。