共计 2280 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点
在传统的聊天应用中,通常采用轮询(Polling)或长轮询(Long Polling)的方式获取服务器的最新消息。这种方式存在几个明显的问题:

- 高延迟 :客户端需要不断向服务器发送请求,无法实时获取消息
- 资源浪费 :大量无效请求占用带宽和服务器资源
- 用户体验差 :消息显示不连贯,有明显的等待感
流式传输技术(如 SSE)可以完美解决这些问题,实现真正的实时对话体验。
技术选型
实现实时通信主要有两种技术方案:
- WebSocket
- 全双工通信
- 适合需要客户端和服务器频繁双向交互的场景
-
实现复杂度较高
-
Server-Sent Events (SSE)
- 服务器单向推送
- 基于 HTTP 协议,实现简单
- 自动重连机制
- 适合只需要服务器推送的场景
对于 ChatGPT 这类以服务器推送为主的场景,SSE 是更合适的选择。
核心实现
建立 SSE 连接
const createSSEConnection = (url: string, onMessage: (data: string) => void) => {const eventSource = new EventSource(url);
eventSource.onmessage = (event) => {onMessage(event.data);
};
eventSource.onerror = () => {eventSource.close();
// 实现自动重连逻辑
setTimeout(() => createSSEConnection(url, onMessage), 1000);
};
return () => eventSource.close();
};
处理分块响应数据
ChatGPT 的流式响应通常是分块传输的 JSON 数据,我们需要:
- 解析每块数据
- 拼接不完整的 JSON
- 更新组件状态
const [state, dispatch] = useReducer(reducer, initialState);
const handleMessage = (data: string) => {
try {const parsed = JSON.parse(data);
dispatch({type: 'APPEND_MESSAGE', payload: parsed.content});
} catch (error) {
// 处理不完整 JSON 的情况
dispatch({type: 'BUFFER_MESSAGE', payload: data});
}
};
状态管理
使用 useReducer 管理复杂状态:
const initialState = {messages: [],
buffer: '',
isConnected: false,
error: null
};
function reducer(state, action) {switch (action.type) {
case 'APPEND_MESSAGE':
return {
...state,
messages: [...state.messages, action.payload],
buffer: ''
};
case 'BUFFER_MESSAGE':
return {
...state,
buffer: state.buffer + action.payload
};
// 其他 case...
}
}
完整代码实现
封装 SSE Hook
import {useEffect, useReducer} from 'react';
interface SSEOptions {onMessage: (data: string) => void;
onError?: (error: Event) => void;
onOpen?: () => void;}
const useSSE = (url: string, options: SSEOptions) => {useEffect(() => {const eventSource = new EventSource(url);
eventSource.onmessage = (event) => {options.onMessage(event.data);
};
eventSource.onerror = (error) => {options.onError?.(error);
eventSource.close();};
eventSource.onopen = () => {options.onOpen?.();
};
return () => {eventSource.close();
};
}, [url]);
};
UI 渲染优化
使用 React.memo 避免不必要的重绘:
const MessageItem = React.memo(({content}: {content: string}) => (<div className="message">{content}</div>
));
生产环境考量
网络中断恢复
- 实现指数退避重连策略
- 在客户端保存未完成的对话状态
- 提供用户手动重连按钮
服务端限流处理
- 监控连接数
- 实现优雅降级
- 添加速率限制
移动端兼容性
- iOS Safari 需要特殊处理
- 考虑移动网络不稳定的情况
- 优化电池消耗
避坑指南
- 内存泄漏
- 确保在组件卸载时关闭 SSE 连接
-
清理所有事件监听器
-
中文乱码
- 确保服务器设置正确的 Content-Type
-
客户端显式指定 UTF- 8 编码
-
iOS Safari 兼容性
- iOS 会冻结后台页面的 SSE 连接
- 解决方案:使用 Web Worker 或轮询作为后备方案
总结
实现 React 中的 ChatGPT 流式对话需要考虑多个方面:从技术选型到状态管理,从错误处理到性能优化。SSE 提供了一种简单高效的解决方案,但在生产环境中还需要考虑网络状况、设备兼容性等各种因素。本文介绍的方法经过了实际项目验证,希望能帮助开发者避开常见陷阱,构建更流畅的聊天体验。
正文完
