Bootstrap

【uni-app多端】修复stmopjs下plus-websocket无心跳的问题

从这篇文章接着向下看:

uniapp plus-websocket 和stompjs连接教程 安卓ios手机端有效 - 简书

按照文章的方式,能够实现APP下stmopjs长连接。但是有一个问题,就是会频繁输出

res-创建连接-1-

 跟踪连接,会发现连接都会在大约40s后掉线断开,然后由于stompjs保活机制又进行重连。在重连过程中,对应的消息接收不到。导致出现部分消息丢失的情况。

目前解决的办法,是自己实现一个心跳逻辑,每隔指定的时间发送。就完成了连接保活。修改如下:

import socket from 'plus-websocket'

class WebSocketPolyfill {
  constructor(url) {
。。。。
  connected() {
    return socket.connected
  }
}

export default WebSocketPolyfill
      client = new Client({
        // #ifndef H5
        webSocketFactory() {
          if (isMp) {
            // 微信小程序
            return new Ws({
              url: amqpServerUrl,
              protocols: ['v12.stomp', 'v11.stomp', 'v10.stomp'] // ← 这是 stomp 协议的默认写法,可供参考
            })
          } else {
            appWs = new WebSocket(amqpServerUrl)
            return appWs
            // Android | IOS
          }
        },

。。。。。

const appHeartbeat = () => {
  setTimeout(() => {
    if (appWs.connected) {
      const buffer = new ArrayBuffer(1) // 创建一个1字节的ArrayBuffer
      const view = new Uint8Array(buffer)
      view[0] = 0x09 // 根据RFC6455, opcode 0x9 表示ping帧

      appWs.send(buffer)
      appHeartbeat()
    }
  }, HEARTBEAT_INTERVAL)
}

然后在onConnect后激活心跳

        onConnect: () => {
          // connect to user channel....

          // #ifdef APP-PLUS
          appHeartbeat()
          // #endif
        },

这样就解决了掉线问题

----------------------[2024/11/21新增]-----------------------

长链接睡死问题的解决
当屏幕休眠超过20分钟时,在IOS及安卓系统可能由于资源释放导致socket无法重连。上面这种方案无法直接断开链接重连。必须通过重载APP解决,因此实现一个变量和两个方法,在APP隐藏显示时进行计算,如果熄屏或挂起超过20分钟,则加载首页来实现长链接重载。

let hideTick: number = -1

export const watchHide = () => {

  hideTick = new Date().getTime()

}



export const watchShow = async () => {

  // 如果休息时间太久,就回首页重置长连接,避免睡死

  if (

    hideTick > 0 &&

    new Date().getTime() - hideTick > FORCE_RECONNECT_ON_SLEEP_SEC &&

    currentUserId

  ) {

    await leaveUserChannel() //deactivate长链接,close socket

    setTimeout(() => {

      // 休息太久了,去首页

      utils.reLaunch('/pages/index/index')

    }, 1000)

  }

  hideTick = -1

}

在APP.vue的show和hide分别执行watchShow和watchHide即可

下面是完整的plus-websocket封装单元(该单元已废弃,由于plus-websocket大并发时丢失消息的问题,已重写替代模块,请见我另一篇《plus-websocket替代websocket封装模块》:

websocket-app.js:

/**
 * 封装 plus-websocket 文件
 */
import socket from 'plus-websocket'

class WebSocketPolyfill {
  constructor(url) {
    // 创建连接
    socket.connectSocket({
      url,
      success: function (res) {
        console.log('res-创建连接-1-', res)
      }
    })

    // 连接开启
    socket.onSocketOpen((res) => {
      this.onopen(res)
    })

    // 连接关闭
    socket.onSocketClose((res) => {
      this.onclose(res)
    })

    // 连接异常
    socket.onSocketError((res) => {
      this.onerror(res)
    })

    // 接收消息
    socket.onSocketMessage((res) => {
      this.onmessage(res)
    })
  }

  /**
   * 连接开启
   */
  onopen(res) {}

  /**
   * 连接关闭
   */
  onclose(res) {}

  /**
   * 连接异常
   */
  onerror(res) {}

  /**
   * 接收消息
   */
  onmessage(res) {}

  /**
   * 发送消息
   */
  send(data) {
    socket.sendSocketMessage({
      data
    })
  }

  /**
   * 关闭连接
   */
  close() {
    socket.closeSocket()
  }

  connected() {
    return socket.connected
  }
}

export default WebSocketPolyfill

;