参考
问题描述
在跟江西团队对接websocket中,使用 useWebSocket 连接后端建立 websocket 连接,不断的连接成功之后又断开,前端代码在其他项目中没有任何问题。
自己反复看js逻辑没有任何问题,于是尝试使用websocket 最原始的方法测试,看看是否会复现不断的连接成功之后又断开的现象,结果没有任何问题。
分析定位
- 我代码中使用了 heartbeat: true ,表示要有心跳,如果后端没有任何返回,则认为断开了连接
- 在长沙后端可能会有心跳返回,但是在江西团队中没有做此设计
解决办法
去掉心跳配置项即可
使用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)
}
}
}