react自定义hook,useWebSocket
1、描述
本来项目的告警和消息提醒是用的接口30秒调用一次,这次要改成webSocket传输。
因为前端是用的https,后端用的http,后端的socket只支持ws
不支持wss
,这里使用了webpack-dev-server
的proxy
代理了一下。
target:ws目标地址、pathRewrite:地址重写,这里是把/aapp_socket重写成aapp/websocket,ws:是否开启socket,secure: 默认情况下不接收转发到https的服务器上,如果希望支持,可以设置为false ,changeOrigin:是否跨域。差不多就这个意思
'/aapp_socket': {
target: `ws://xxx.xxx.xxx/`,
pathRewrite: {
'^/aapp_socket': 'aapp/websocket',
},
ws: true,
secure: false,
changeOrigin: true,
},
使用连接的地址:
`wss://localhost:3000/aapp_socket`;
实际的访问的地址就是:
`ws://xxx.xxx.xxx/aapp/websocket
2、代码
这里socket,没有配置心跳监测,还是通过我主动去推送来获取信息。这里是获取告警数和消息数量,
首先绑定websocket的事件。主要就是在message的事件中,连接成功后端返回的是sucess,就不做操作。后面就是判断返回的消息格式是否正确,如果不正确就重新连接。
还可以把获取消息的时间间隔,和重新连接间隔,地址等变量抽出来,作为参数传进来。
import {useCallback, useRef, useState, useEffect} from 'react';
const token = window.localStorage.getItem('authorization');
const userId = JSON.parse(window.localStorage.getItem('userInfo') || '')?.id;
// 获取告警数量
const UNREAD_WARN_COUNT = 'UNREAD_WARN_COUNT';
// 获取消息数量
const UNREAD_MSG_COUNT = 'UNREAD_MSG_COUNT';
// 获取消息的间隔
const INT_TIME = 5000;
// websocket状态
const webSocketStatus = {
CONNECTING: 0,
OPEN: 1,
CLOSING: 2,
CLOSED: 3,
};
const useWebSocket = () => {
const [reset, setReset] = useState<boolean>(false);
const socket = useRef<WebSocket>();
const sendCount = useRef<number>(1);
const [alarmCount, setAlarmCount] = useState<number>(0);
const [messageCount, setMessageCount] = useState<number>(0);
// 开启事件,主动获取数据
const socketOnOpen = useCallback(() => {
// 判断连接状态是不是open
if (socket?.current?.readyState === webSocketStatus.OPEN) {
// 第一次加载触发一次
socket?.current?.send(JSON.stringify({businessKey: [UNREAD_MSG_COUNT, UNREAD_WARN_COUNT]}));
}
const timer = setInterval(() => {
if (socket?.current?.readyState === webSocketStatus.OPEN) {
socket?.current?.send(JSON.stringify({businessKey: [UNREAD_MSG_COUNT, UNREAD_WARN_COUNT]}));
}
}, INT_TIME);
// 返回信息出错清除定时器
if (sendCount.current === 0) {
clearInterval(timer);
setReset(true);
}
}, [sendCount]);
// 关闭事件重新连接
const socketOnClose = useCallback(() => {
setReset(true);
}, []);
// 出错事件
const socketOnError = useCallback((err: any) => {
console.log('err: ', err);
}, []);
// 收发信息
const socketOnMessage = useCallback(
(e: any) => {
if (e.data === 'success') return;
const alarmCountObj = JSON.parse(e.data);
const paramNameArr = Object.keys(alarmCountObj);
// 判断返回告警保持连接否则断开连接
if (paramNameArr[1] === 'UNREAD_WARN_COUNT') {
sendCount.current += 1;
setAlarmCount(alarmCountObj.UNREAD_WARN_COUNT);
setMessageCount(alarmCountObj.UNREAD_MSG_COUNT);
} else {
sendCount.current = 0;
}
},
[sendCount],
);
// 初始化连接socket
const socketInit = useCallback(() => {
try {
const scoketUrl = `wss://${window.location.host}/aapp_socket/${userId}/${token}`;
const socketObj = new WebSocket(scoketUrl);
socketObj.addEventListener('close', socketOnClose);
socketObj.addEventListener('error', socketOnError);
socketObj.addEventListener('message', socketOnMessage);
socketObj.addEventListener('open', socketOnOpen);
socket.current = socketObj;
sendCount.current = 1;
} catch (err) {
console.log('err: ', err);
}
}, [socketOnClose, socketOnError, socketOnMessage, socketOnOpen]);
// 初始化连接socket
useEffect(() => {
socketInit();
}, [socketInit]);
// 断线重连
useEffect(() => {
if (!reset) return;
setTimeout(() => {
socketInit();
setReset(false);
}, 30000);
}, [reset, socketInit]);
return [alarmCount, messageCount];
};
export default useWebSocket;
使用
// 告警socket连接
const [alarmCount, messageCount] = useWebSocket();