vueuse 开发websocket (重连机制)

文章描述了一个开发人员在使用vueuse库的useWebSocket与江西团队的WebSocket服务交互时遇到的问题,连接不断断开。经过分析发现,由于设置了心跳检测,而在江西团队环境中后端没有相应心跳响应,导致连接自动关闭。解决办法是移除心跳配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考

  1. vueuse useWebSocket

问题描述

在跟江西团队对接websocket中,使用 useWebSocket 连接后端建立 websocket 连接,不断的连接成功之后又断开,前端代码在其他项目中没有任何问题。

自己反复看js逻辑没有任何问题,于是尝试使用websocket 最原始的方法测试,看看是否会复现不断的连接成功之后又断开的现象,结果没有任何问题。

分析定位

  1. 我代码中使用了 heartbeat: true ,表示要有心跳,如果后端没有任何返回,则认为断开了连接
  2. 在长沙后端可能会有心跳返回,但是在江西团队中没有做此设计

解决办法

去掉心跳配置项即可

使用vueuse库

<template>
  <div class="warehouseCenterIndex absolute inset-x-0 inset-y-0">
    <template v-for="(item, i) in cameraArr" :key="item.cameraIndexCode + i">
      <CameraOnMap v-if="!item.hasAlarm" :info="item"></CameraOnMap>
      <WarnOnMap v-else :info="item"></WarnOnMap>
    </template>
    <template v-if="warnInfo">
      <CameraOnMap v-if="!warnInfo.hasAlarm" :info="warnInfo"></CameraOnMap>
      <WarnOnMap v-else :info="warnInfo" :detail="true"></WarnOnMap>
    </template>
  </div>
</template>

<script setup>
import {cameraInfo} from '@/api/armyScreenApi.js'
import CameraOnMap from '@/views/armyScreen/warehouse/center/CameraOnMap.vue'
import WarnOnMap from '@/views/armyScreen/warehouse/center/WarnOnMap.vue'
import { useWebSocket } from '@vueuse/core'
import $bus from "@/util/bus";

const ipPort = import.meta.env.DEV ? '10.192.195.150:8080' : window.location.host
const wsUrl = `${location.protocol === 'http:' ? 'ws://' : 'wss://'}${ipPort}/csjzzav/realtime/alarm`
console.log('wsUrl', wsUrl)
const warnInfo = ref(null)
/**
 * status 是连接的状态值
 * data 是 socket 推送过来的消息
 * send 是一个方法, 用来发送消息给后台
 * close 是一个方法,关闭 socket 连接
 * open 。。。不知道
 */
const { status, data, send, open, close  } = useWebSocket(wsUrl, {
  onConnected: function (ws) {
    console.log('websocket 连接成功!', ws)
  },
  onDisconnected: function (ws, event) {
    console.log('onDisconnected')
  },
  onError: function (ws, event) {
    console.log('onError')
  },
  onMessage: function (ws, event) {
    console.log('event.data', event.data)
    if (event.data) {
      const info = JSON.parse(event.data)
      console.log(info)
      warnInfo.value = info
    }
  },
  // heartbeat: true,
  // heartbeat: {
  //   message: 'ping',
  //   interval: 1000,
  //   pongTimeout: 1000,
  // },
  /*
  * 不使用心跳,根据后台实际逻辑来,有时候发送心跳,不会返回任何数据,但是不会断开
  * 如果设置为 true,表示需要心跳,发送心跳后,后台一定要返回信息,不然就会断开重连
  * */
  heartbeat: false,
  // autoReconnect: true,
  autoReconnect: {
    retries: 3,
    delay: 2000,
    onFailed() {
      alert('Failed to connect WebSocket after 3 retires')
    },
  },
  autoClose: true,
})

/************/
onMounted(()=> {
  cameraInfoService()
  $bus.on('reRequest', cameraInfoService)
})
onBeforeUnmount(() => {
  $bus.off('reRequest', cameraInfoService)
})
/************/
const cameraArr = ref([])

function cameraInfoService() {
  cameraInfo().then(res => {
    console.log(res)
    cameraArr.value = res.data || []
  })
}

</script>

根据原生 socket API

import { ajaxCtx } from '@/api/config.js'
export default {
  data () {
    return {
      websocket: null,
      lockReconnect: false, // websokect 锁
      heartBeatTime: 5 * 60 * 1000, // 心跳检测时长
      timer: null // 定时变量
    }
  },
  beforeDestroy () {
    this.websocket && this.websocket.close()
  },
  methods: {
    /**
     * @desc 初始化websocket
     */
    initWebsocket () {
      // 检查浏览器是否支持 webscoket
      if ('WebSocket' in window) {
        // https 对应 wss 协议  ;  http 对应 ws 协议
        const wsUrl = `${location.protocol === 'http:' ? 'ws://' : 'wss://'}${ajaxCtx.socket}/api/socket/`
        console.log(wsUrl)
        this.websocket = new WebSocket(wsUrl)
        this.websocket.onopen = res => {
          console.log('WebSocket连接成功')
          // 再次创建一个定时器,指定的时间之后发送message消息
          this.resetHeart().startHeart()
        }
        // 接收到消息触发的事件
        this.websocket.onmessage = res => {
          // 再次创建一个定时器,指定的时间之后发送message消息
          this.resetHeart().startHeart()
          const backData = JSON.parse(res.data)
          console.log(backData)
          const _data = backData?.params?.events[0]?.data
          if (_data) {
            console.log('拿到数据,前端做逻辑处理')
          }
        }
        // 连接出错,重连
        this.websocket.onerror = () => {
          this.reconnectWs()
          this.$message.error('WebSocket连接失败,请刷新当前页面!')
        }
        // websocket 关闭连接
        this.websocket.onclose = res => {
          // this.reconnectWs()
        }
      } else {
        this.$message.warning('当前浏览器 Not support websocket')
      }
    },
    /**
     * @desc 重连机制
     */
    reconnectWs () {
      if (this.lockReconnect) return
      this.lockReconnect = true
      this.initWebsocket()
      // 没连接上会一直重连,设置延迟避免请求过多
      setTimeout(() => {
        this.lockReconnect = false
      }, 1000)
    },
    /**
     * @desc 重置定时
     */
    resetHeart () {
      if (this.timer) {
        // 重置定时
        clearTimeout(this.timer)
      }
      return this
    },
    /**
     * @desc 开始Ws
     */
    startHeart () {
      // 开启定时
      this.timer = setTimeout(() => {
        // 心跳时间内收不到消息,主动触发连接关闭,开始重连
        this.websocket.send(JSON.stringify({ isExit: 'exit' }))
      }, this.heartBeatTime)
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值