uniapp中websocket关闭失败问题解决,防止一个应用多个websocket实例并清理不彻底

386 阅读2分钟

前端开发websocket的过程是页面初始化后创建了websocket长连接,然后心跳检测,在意外关闭后重重连websocket,离开页面后就对websocket进行销毁,这是很正常的逻辑。

然后在开发过程发现一个问题,离开页面后定时器依然在检测心跳,而且离开后会关闭一次然后被重新连接了,这会导致后台推送数据的时候多次重复出现,甚至在多个不同聊天人之间也出现原来的用户聊天推送(在其它端口推送时,后台根据用户id推送)。

之前前端同事对接出现这个问题就没解决,后台是没问题的,那个同事说处理不了就不处理了,虽然我知道是严重的消息乱串问题,但是说不服,说多两次就让我自己写前端了,哈哈哈。

现在我自己用UNAIPP开发自己的商城项目,自己图手写了个聊天客服,如下图一样。然后发现了这个问题是普遍存在的,而且就是前端未能清理socket的问题,导致消息混乱。

image.png

image.png 一开始页面的清理是这样的(仅展示重点部分)

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'
    })
  }
},

就这个小小的状态就把问题解决了