WebSocket 封装说明
以下集成内容仅对封装思想进行说明,如需进行代码对照,可参考目录下 react19_ts 项目内实际代码,文档与代码会在git上持续补充
git仓库地址:https://gitee.com/xiaoli-account/react19_ts> 源码路径:src/layout/utils/websocket.ts
> 基于原生 WebSocket 的类封装,提供基础的连接管理、断线重连、以及状态与消息的事件订阅机制。
> 通过实例化调用消息接收、发送、异常、连接函数,适用于前后端双向实时通信场景。
代理配置
在 `vite.config.ts` 中配置 WS 代理:
// WebSocket 代理配置...(env.VITE_APP_WS_ENDPOINT && { [env.VITE_WS_BASE_URL]: { target: env.VITE_APP_WS_ENDPOINT.replace('wss://', 'https://').replace('ws://', 'http://'), changeOrigin: true, ws: true, rewrite: (path) => path.replace(new RegExp('^' + env.VITE_WS_BASE_URL), ''), },}),
核心功能
- 防止重复连接:`connect()` 调用时会检查现有实例与状态,避免产生冗余连接。
- 断线自动重连:通过 `reconnectInterval` 和 `maxReconnectAttempts` 支持配置定时自动重连机制。
- 消息自动解析:在 `onmessage` 阶段会自动 `try/catch` 执行 `JSON.parse`,解析失败则回退返回原始数据。
- 统一状态管理:暴露原生的 `WebSocketState` 枚举(`CONNECTING: 0`, `OPEN: 1`, `CLOSING: 2`, `CLOSED: 3`),并支持通过 `onStateChange` 观测状态流转。
API 文档
配置参数 (`WebSocketConfig`)
- `url` _(必需)_:请求路径。内部会自动结合环境变量 `.env` 下的 `VITE_WS_BASE_URL` 进行前缀拼接。
- `reconnectInterval` _(可选)_:断线后发起重连尝试的间隔时间(毫秒)。
- `maxReconnectAttempts` _(可选)_:最大重连尝试次数,若不设置则无限重连。
实例方法
- `.connect()`:发起 WebSocket 握手。
- `.disconnect()`:主动断开连接,并清理重连相关的定时器。
- `.send(data)`:发送消息。内部限制仅在 `OPEN` 状态下执行发送。支持传入 `string | ArrayBufferLike | Blob | ArrayBufferView` 等原生允许类型。
- `.getState()`:获取当前连接的状态枚举值。
事件订阅
- `.onMessage((data) => void)`:监听消息接收。
- `.onError((error) => void)`:监听 WebSocket 抛出的异常。
- `.onStateChange((state) => void)`:监听 `readyState` 的状态流转。
业务接入示例
完整示例可参考:`src/pages/examples/websocket-example/index.tsx`
import { useEffect, useRef, useState } from "react";import { SimpleWebSocket, WebSocketState } from "@/layout/utils/websocket";const WebsocketExample = () => { const [connState, setConnState] = useState<number>(WebSocketState.CLOSED); const wsRef = useRef<SimpleWebSocket | null>(null); // 组件卸载时主动断开连接,避免内存泄漏与无效连接 useEffect(() => { return () => { wsRef.current?.disconnect(); }; }, []); const handleConnect = () => { // 避免重复建立连接 if (wsRef.current && wsRef.current.getState() === WebSocketState.OPEN) return; // 1. 实例化 const ws = new SimpleWebSocket({ url: "/ws", reconnectInterval: 3000, maxReconnectAttempts: 3, }); wsRef.current = ws; // 2. 状态映射及事件订阅 ws.onStateChange((state) => { setConnState(state); // state 映射: 0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED }); ws.onMessage((data) => { // 这里的 data 已底端静默处理过 JSON.parse console.log('接收到数据:', data); }); ws.onError((e) => { console.error('WebSocket 连接异常:', e); }); // 3. 执行真实连接 ws.connect(); }; const handleSend = () => { // 确保连接在 OPEN 状态下再抛出消息 if (!wsRef.current || connState !== WebSocketState.OPEN) return; // 建议业务层根据后端协议统一对发送内容做序列化处理 wsRef.current.send(JSON.stringify({ type: "ping" })); }; return ( <div> <p>当前状态: {connState}</p> <buttononClick={handleConnect}disabled={connState === WebSocketState.OPEN}>建立连接</button> <buttononClick={handleSend}disabled={connState !== WebSocketState.OPEN}>发送 Ping</button> <buttononClick={() => wsRef.current?.disconnect()}>手动断开</button> </div> );}