SSE请求封装
以下集成内容仅对思想进行说明,如需进行代码对照,可参考目录下 react19_ts 项目内实际代码,文档与代码会在git上持续补充
git仓库地址:https://gitee.com/xiaoli-account/react19_ts> 封装基于底层的sse函数:src/layout/utils/sse.ts
> 在底层sse的基础上对sse.ts的使用进行react使用的hook封装,具体可查看项目文件:src/hooks/use-sse.tsx
> sse请求适用于服务端单方面进行通知的应用场景,类似于1/2的WebSocket
sse请求代理配置
// SSE 代理配置...(env.VITE_APP_SSE_ENDPOINT && { [env.VITE_SSE_BASE_URL]: {target: env.VITE_APP_SSE_ENDPOINT,changeOrigin: true,secure: false,rewrite: (path) => path.replace(new RegExp('^' + env.VITE_SSE_BASE_URL), ''), },}),
useSSE Hook 使用说明
`useSSE` 提供了面向 React 函数组件的 SSE (Server-Sent Events) 状态管理与连接控制,完全剥离了原生的事件监听器添加/移除逻辑,将推送流数据化为 React 可直接绑定的响应式状态。
1. 类型定义与参数说明
// Hook 签名function useSSE(url: string, options?: UseSSEOptions): UseSSEReturn;// 配置选项 (扩展自底层的 SSEClientOptions)interface UseSSEOptions { method?: "GET" | "POST"; // 请求方法,默认为 POST autoConnect?: boolean; // 是否在组件挂载时自动连接,默认 true maxEvents?: number; // 日志/消息记录最大保留数,默认 100 formatMessage?: (data: string) => any; // 自定义数据清洗/格式化函数 eventListeners?: { // 自定义各阶段回调 onOpen?: (event) => void; onMessage?: (data, event) => void; onError?: (event) => void; onClose?: (event) => void; }; // 同时支持底层的 headers, body, queryParams, reconnectInterval 等配置...}
2. 返回值说明 (UseSSEReturn)
在组件中使用 Hook 后,会返回一组完全响应式的连接状态与触发操作的手柄:
- `state`: 当前连接详情对象
- `connectionStatus`: 易读的推流状态枚举 `"disconnected" | "connecting" | "connected" | "error" | "reconnecting"`
- `isConnected` / `isConnecting`: 状态简写布尔标识
- `lastMessage` / `lastError`: 最近一次触发的消息/错误对象
- `reconnectAttempts`: 当前自动重连机制尝试的次数
- `messages`: 通过 `onMessage` 处理并累积的消息数组流
- `eventHistory`: 完整的生命周期级事件池(包含了 open、message、error 等动作踪迹,并会受限于 `maxEvents` 数量自动挤出陈旧数据)
- `connect() / disconnect() / reconnect()`: 暴露用于外部对 SSE 推流通道进行手动的开闭和重试控制
- `clearMessages()`: 手动将当前的 `messages` 与 `eventHistory` 推拽入空数组进而释放页面内存
- `addEventListener(type, handler) / removeEventListener(type)`: 满足复杂场景:除了捕捉无类型标记的基础 message 外,支持注册并收听后端下发的非基础类型名的特殊具名事件。
3. 完整示例使用
基于示例文件 (`src/pages/examples/sse-example/index.tsx`) 提炼:
import { useMemo } from "react";import { useSSE } from "@/hooks/use-sse.tsx";const SseExample = () => { // 推荐使用 useMemo 包装 Options 避免配置对象被重复实例化,由此引发内部 useEffect 被迫进行非预期的重连机制 const sseOptions = useMemo( () => ({ method: "GET" as const, autoConnect: false, // 停止挂载即连接默认行为,选择由外部按钮手动操控 maxEvents: 20, // 高频刷表场景中防止爆内存,限制缓存 20 条日志 // formatMessage 作为中间件拦截器,作用是将未经修饰的原始 text 字符串统一安全映射为标准可用结构格式 formatMessage: (data: string) => { try { const d = JSON.parse(data); return { user: d.user, title: d.title, wiki: d.wiki, }; } catch (e) { return data; } }, // Hook 内部封装好的一系列流程动作透传,主要方便在应用业务上挂载 console 回路追踪 eventListeners: { onOpen: (event: any) => console.log("连接建立:", event), onMessage: (data: any, event: any) => console.log("收到消息:", data), onError: (event: any) => console.error("连接错误:", event.error), onClose: (event: any) => console.log("连接关闭:", event), }, }), [] ); // Hook 驱动开始,利用 React 解构拿取所有我们需要映射到 JSX 层级的属性块 const { state, eventHistory, connect, disconnect, reconnect, clearMessages } = useSSE("/v2/stream/recentchange", sseOptions); return ( <div> <p>当前连接状态指示器: {state.connectionStatus}</p> {/* SSE 行为控制组 */} <buttononClick={() => connect()} disabled={state.isConnected}>开始连接</button> <buttononClick={() => disconnect()} disabled={!state.isConnected}>断开连接</button> <buttononClick={clearMessages}>清出界面日志</button> {/* 实时动态消息滚动渲染池 */} <div> <h3>系统级网络流踪迹记录 (最新 {eventHistory.length} 笔):</h3> {eventHistory.map((item, index) => ( <divkey={index}> <span>[{item.timestamp.toLocaleTimeString()}]</span> <spanstyle={{margin: "08px", color: "blue" }}>[{item.type.toUpperCase()}]</span> <span>{typeof item.data === "object" ? JSON.stringify(item.data) : String(item.data)}</span> </div> ))} </div> </div> );};export default SseExample;