webScoket重连机制,心跳机制

发布时间 2023-09-12 10:47:06作者: 幻影之舞

webScoket可以实时获取数据,做到实时渲染的效果,但ws一直连接着还好,万一网络波动,断了呢。。。。

那只能刷新页面,重新连接,但又不晓得啥时候断了,这时候就要用到心跳机制,对ws进行监视

// WebSocket连接地址
const wsUrl = ref('')
// Ws实例
const ws = ref()
onMounted( () => {
    getId()     // 获取用户id,利用id进行ws链接,否则会出现多用户打开断的情况。需要后端处理,
})
const getId = () => {
  wsUrl.value = `${import.meta.env.VITE_WS}/processLog/socket/${userInfo.value.id}` // 这里在env.pro和env.dev里设置下VITE_WS变量(不要带引号),最后面是拿用户的id
    ws_create(wsUrl.value)
}
// 创建WebSocket
function ws_create(url: string) {
  try {
    // 判断是否支持 WebSocket
    if ('WebSocket' in window) {
      // 连接WebSocket
      ws.value = new WebSocket(url)
      // 初始化WebSocket事件(WebSocket对象, WebSocket连接地址)
      ws_event(ws.value, url)
    }
  } catch (e) {
    // 重新连接WebSocket
    ws_recontent(url)
    console.log('重新连接')
  }
}
// WebSocket 事件创建
function ws_event(ws: any, url: string) {
  ws.onopen = function (event: any) {
    // 心跳检测重置
    ws_heartCheck.reset().start()
    console.log('WebSocket已连接')
  }

  ws.onclose = function (event: any) {
    // 重新连接WebSocket
    ws_recontent(url)
    console.log('WebSocket连接已关闭')
  }

  ws.onerror = function (event: any) {
    // 重新连接WebSocket
    ws_recontent(url)
    console.log('WebSocket错误:', event)
  }

  ws.onmessage = function (event: any) {
    // 只要有数据,那就说明连接正常
    ws_heartCheck.reset().start()
    // 处理数据,只处理非心跳检测的数据
    const result = JSON.parse(event.data)
    console.log(result, 'result')
   // 处理数据逻辑
  }
}
// 重新连接websocker(WebSocket连接地址)
function ws_recontent(url) {
  // 延迟避免请求过多
  setTimeout(() => {
    ws_create(wsUrl.value)
  }, 3000)
}
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,这样服务端会抛异常。
window.onbeforeunload = function () {
  ws.value.close()
}

// 核心逻辑  根据后端在规定时间内返回的心跳数据进行判断。比如后端5s返回一次心跳数据,定时器就设在5s左右,如果有数据返回,就直接进到ws.onMessage里了,如果没有,超过了定时器的时间,就会close这次链接,然后在规定的几秒后进行重新连接,也就是ws_recontent方法,时间就是3s

// 10秒一次心跳
const timeOut = ref(10000)
// 执行心跳的定时器
const timeoutObj = ref()
// 服务器超时定时器
const serverTimeoutObj = ref()
// WebSocket心跳检测
var ws_heartCheck = {
  reset() {
    // 重置方法
    clearTimeout(timeoutObj.value)
    clearTimeout(serverTimeoutObj.value)
    return this
  },
  start() {
    // 启动方法
    timeoutObj.value = setTimeout(() => {
      // 这里发送一个心跳信息,后端收到后,返回一个消息,在onmessage拿到返回的心跳(信息)就说明连接正常
      // ws.value.send('check')
      // 如果超过一定时间还没重置,说明后端主动断开了
      serverTimeoutObj.value = setTimeout(() => {
        // 如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
        ws.value.close()
      }, timeOut.value)
    }, timeOut.value)
  },
}