本篇文章讲前端向基于React框架以及TypeScript进行websocket的封装,例子可以直接使用。
由于业务中需要开发一个类似客服回复的实时通讯,所以用了最基本的
WebSocket
,如果是node
做后端服务,可以使用socket.io
框架,它提供了很多高级连接的方法,这是他的文档socket.io/zh-CN/docs/…
一张图简单看下ws和request的区别
通过图相信大家很清晰就能看出区别所在,接下来上代码
1.封装WebSocket
首先在项目中新建一个WebSocket
的ts文件,加入以下代码,代码可以直接使用,无需改动
这是我写的一个Hook,大家可以借鉴一下,十分清晰,代码中有写明注释
import { useEffect, useRef, useState } from 'react';
//消息类型,下面的代码我用any类型,不建议用any,大家可以自己声明Message类型,为了方便我暂时用any 不用Message
type Message = {
type: string;
data: any;
};
type WebSocketOptions = {
url: string;
onOpen?: () => void;
onClose?: (event: Event) => void;
onError?: (event: Event) => void;
onMessage?: (message: any) => void;
reconnectInterval?: number;
reconnectAttempts?: number;
};
const defaultOptions: Required<WebSocketOptions> = {
url: '',//连接的长链接
onOpen: () => {},//开启连接
onClose: () => {},//关闭链接
onError: () => {},//异常
onMessage: () => {},//消息
reconnectInterval: 1000,//重连时长设置
reconnectAttempts: Number.MAX_VALUE,//最大连接范围数
};
const useWebSocket = (
options: WebSocketOptions,
): [WebSocket | undefined, (message: any) => void, string, boolean] => {
const { url, onOpen, onClose, onError, onMessage, reconnectInterval, reconnectAttempts } = {
...defaultOptions,
...options,
};
const [isConnected, setIsConnected] = useState(false);//是否连接
const [reconnectCount, setReconnectCount] = useState(0);//用于判断重连
const [lastMessage, setLastMessage] = useState('');//最新的消息
const socketRef = useRef<WebSocket>();
const reconnectTimerRef = useRef<NodeJS.Timer>();
const connect = () => {
//连接函数封装
setIsConnected(false);
const socket = new WebSocket(url);
socket.onopen = () => {
//开始连接
console.log('WebSocket is connected');
setIsConnected(true);
setReconnectCount(0);
onOpen();
};
socket.onclose = (event) => {
//连接关闭
console.error(`WebSocket closed with code ${event.code}`);
setIsConnected(false);
onClose(event);
if (reconnectCount < reconnectAttempts) {
//用于判断断开连接后重新连接
reconnectTimerRef.current = setTimeout(() => {
setReconnectCount((prevCount) => prevCount + 1);
connect();
}, reconnectInterval);
}
};
socket.onerror = (event) => {
//异常问题
console.error('WebSocket error:', event);
onClose(event);
};
socket.onmessage = (event) => {
//接收到消息
const message: any = JSON.parse(event.data);
console.log(`WebSocket received message: ${message}`);
setLastMessage(event.data);
onMessage(message);
};
socketRef.current = socket;
};
useEffect(() => {
connect();
return () => {
socketRef.current?.close();
clearTimeout(reconnectTimerRef.current);
};
}, []);
const sendMessage = (message: any) => {
//用于发送消息
if (isConnected && socketRef.current) {
console.log(`WebSocket sending message: ${JSON.stringify(message)}`);
socketRef.current.send(JSON.stringify(message));
} else {
console.error('Cannot send message - WebSocket is not connected');
}
};
//暴露出我们需要的
return [socketRef.current, sendMessage, lastMessage, isConnected];
};
export default useWebSocket;
2. 在项目中引入
//我是放在hooks文件夹下
import useWebSocket from '@/hooks/websocket';
.....
.....
//注意https的url下需要使用 wss ,http是需要使用 ws
const [webSocket, sendMessage, lastMessage, isConnected] = useWebSocket({
url: 'wss://xxxxxxxxxxxxxxx', //这里放长链接
onOpen: () => {
//连接成功
console.log('WebSocket connected');
},
onClose: () => {
//连接关闭
console.log('WebSocket disconnected');
},
onError: (event) => {
//连接异常
console.error('WebSocket error:', event);
},
onMessage: (message) => {
//收到消息
console.log('WebSocket received message:', message);
},
});
.....
.....
3. 使用方法和说明
- 发送消息是用
sendMessage
//和后端约定好消息发送格式,一般需要登陆的话可以先发送一个用户登陆的消息,用作标识
sendMessage({});
- 最新消息可以直接在
lastMessage
中拿到 isConnected
用于判断是否连接webSocket
是暴露出来的整体,你可以我们封装下的所有方法
注:正常来说需要一个心跳来保持,这个需要和后端进行沟通,前端需要隔多少秒发送一个ping
,来检测连接是否正常,否则立马重连
以上就是WebSocket
的基本内容,满足大致需求,如果有更好的建议,欢迎指出探讨,如果是需要开速实现一个简易的WebSocket
可以借鉴