uniapp 使用websocket通信

2,579 阅读1分钟

若是原生浏览器WebSocket,请参考

一、核心代码

1.1 封装WebSocket

@/common/utils/webSocket.js

class webSocketClass {
  constructor(userId, time = 60) {// userId => 用户id
    // 注意:这里取自己项目的websocket地址
    this.url = `ws://h5demo.funversy.com/message/websocket/socket.io/?transport=websocket&userId=${userId}&type=message`
    this.data = null
    this.isCreate = false // WebSocket 是否创建成功
    this.isConnect = false // 是否已经连接
    this.isInitiative = false // 是否主动断开
    this.timeoutNumber = time // 心跳检测间隔
    this.heartbeatTimer = null // 心跳检测定时器
    this.reconnectTimer = null // 断线重连定时器
    this.socketExamples = null // websocket实例
    this.againTime = 3 // 重连等待时间(单位秒)
  }

  // 初始化websocket连接
  initSocket() {
    const _this = this
    this.socketExamples = uni.connectSocket({
      url: _this.url,
      header: {
        'content-type': 'application/json'
      },
      success: (res) => {
        _this.isCreate = true
        console.log(res)
      },
      fail: (rej) => {
        _this.isCreate = false
        console.error(rej)
      }
    })
    this.createSocket()
  }

  // 创建websocket连接
  createSocket() {
    if (this.isCreate) {
      console.log('WebSocket 开始初始化')
      // 监听 WebSocket 连接打开事件
      try {
        this.socketExamples.onOpen(() => {
          console.log('WebSocket 连接成功')
          this.isConnect = true
          clearInterval(this.heartbeatTimer)
          clearTimeout(this.reconnectTimer)
          // 打开心跳检测
          this.heartbeatCheck()
        })
        // 监听 WebSocket 接受到服务器的消息事件
        this.socketExamples.onMessage((res) => {
            console.log('接收webSocket消息', res);
            let msg = res.data;

            if(msg.includes('42["/topic/message"')) {
                // 注意点:此处对接收的消息进行处理,然后发射全局事件(socket-message)
                uni.$emit('socket-message', JSON.parse(msg.split('42')[1])[1]);
            }
        })
        // 监听 WebSocket 连接关闭事件
        this.socketExamples.onClose(() => {
          console.log('WebSocket 关闭了')
          this.isConnect = false
          this.reconnect()
        })
        // 监听 WebSocket 错误事件
        this.socketExamples.onError((res) => {
          console.log('WebSocket 出错了')
          console.log(res)
          this.isInitiative = false
        })
      } catch (error) {
        console.warn(error)
      }
    } else {
      console.warn('WebSocket 初始化失败!')
    }
  }

  // 发送消息
  sendMsg(value) {
    const param = JSON.stringify(value)
    return new Promise((resolve, reject) => {
      this.socketExamples.send({
        data: param,
        success() {
          console.log('消息发送成功')
          resolve(true)
        },
        fail(error) {
          console.log('消息发送失败')
          reject(error)
        }
      })
    })
  }

  // 开启心跳检测
  heartbeatCheck() {
    console.log('开启心跳')
    this.data = { state: 1, method: 'heartbeat' }
    this.heartbeatTimer = setInterval(() => {
      this.sendMsg(this.data)
    }, this.timeoutNumber * 1000)
  }

  // 重新连接
  reconnect() {
    // 停止发送心跳
    clearTimeout(this.reconnectTimer)
    clearInterval(this.heartbeatTimer)
    // 如果不是人为关闭的话,进行重连
    if (!this.isInitiative) {
      this.reconnectTimer = setTimeout(() => {
        this.initSocket()
      }, this.againTime * 1000)
    }
  }

  // 关闭 WebSocket 连接
  closeSocket(reason = '关闭') {
    const _this = this
    this.socketExamples.close({
      reason,
      success() {
        _this.data = null
        _this.isCreate = false
        _this.isConnect = false
        _this.isInitiative = true
        _this.socketExamples = null
        clearInterval(_this.heartbeatTimer)
        clearTimeout(_this.reconnectTimer)
        console.log('关闭 WebSocket 成功')
      },
      fail() {
        console.log('关闭 WebSocket 失败')
      }
    })
  }
}

export default webSocketClass

1.2 WebSocket实例化 与 关闭WebSocket

说明: 此处我用两个函数封装 WebSocket实例化 与 关闭WebSocket,实际开发一般都是结合vuex使用的

// WebSocket实例化
function initSocket(userId){// userId => 用户id
    if(userId){
        if (getApp().globalData.socketObj) {
            // 如果sockt实例未连接
            if (!getApp().globalData.socketObj.isConnect) {
               getApp().globalData.socketObj.initSocket()
            }
        } else {
            // 如果没有sockt实例,则创建
            const data = getAppInfo().globalData.user
            getApp().globalData.socketObj = new WebSocketClass(userId,60)
            getApp().globalData.socketObj.initSocket()
        }
    }
}

// 关闭WebSocket
function closeSocket() {
    if(getApp().globalData.socketObj && getApp().globalData.socketObj.isConnect){
        getApp().globalData.socketObj.closeSocket()
    }
}

1.3 全局弹窗

参考demo,请结合实际ui页面自行修改

image.png

二、思路描述

  1. 在登录成功后,调用一、1.2WebSocket实例化 与 关闭WebSocket中的 initSocket(用户id)。同时在App.vue的 onLaunch 钩子中也调用该函数(作用是:应用刷新时,重新初始化websocket)
  2. 在全局弹框组件中,监听全局事件socket-message(该事件由一、1.1封装WebSocket发出),拿到服务器数据,结合vuex进行业务处理
  3. 退出登录后,调用一、1.2WebSocket实例化 与 关闭WebSocket中的 closeSocket()