React 流式输出 LLM:从 Fetch 到生产环境的完整接入指南
为什么 React 聊天应用必须使用流式响应
普通请求会等待模型完整生成后才返回内容,用户往往会看到数秒甚至更长时间的空白。流式响应则让 token 在生成过程中持续到达前端,界面可以像 ChatGPT 一样逐字更新。对于代码解释、长文生成和客服场景,这不仅改善体感速度,也能让用户更早发现答案方向不对并停止生成。
59API 提供兼容 OpenAI SDK 的接口,基础地址为 https://api.59api.com,可按量付费调用 Claude Opus、Sonnet、Haiku、Fable 与 GPT 模型。它适合需要控制成本的原型和生产项目:接入方式保持 OpenAI 生态习惯,同时使用官方原生质量模型,无需为不同供应商重写前端交互逻辑。
第一步:在服务端创建安全的流式代理
不要把 59API Key 放进 React 的环境变量并打包到浏览器。任何用户都能从开发者工具中取得前端代码和密钥。应在 Next.js Route Handler、Express 或云函数中建立一个 POST 接口,例如 /api/chat,由浏览器只提交 messages、model 和可选参数。
服务端读取 59API Key,并向 OpenAI 兼容的 chat completions 接口发送请求。请求体需要包含 model、messages 与 stream: true。将服务端的响应体直接转发给浏览器,同时设置 Content-Type 为 text/event-stream、Cache-Control 为 no-cache,以及 Connection 为 keep-alive。若使用 Nginx,还应关闭该路径的 proxy_buffering;否则代理会攒够内容才转发,流式效果会消失。
模型选择应按任务分层:短问答可优先选 Haiku,日常分析可选 Sonnet,复杂推理再选择 Opus。通过 59API 的按量计费方式,可在不牺牲接口兼容性的前提下,为不同请求使用更合适的成本档位。
第二步:在 React 中逐块读取响应
提交消息后,用 fetch 调用 /api/chat,并创建 AbortController。检查 response.ok 后,从 response.body.getReader() 获取读取器,再用 TextDecoder 将 Uint8Array 转为文本。SSE 数据通常以 data: 开头,并以空行分隔;前端应保留跨数据块未结束的残余文本,再逐行解析完整事件。
每个有效事件都是 JSON,增量文本通常位于 choices[0].delta.content。收到内容后不要直接修改旧数组:使用 setMessages,并以函数式更新方式替换最后一条 assistant 消息的 content。这样 React 在快速到达的多个 token 下仍能得到正确状态。服务端发送 data: [DONE] 时关闭读取器,并把 loading 状态改为 false。
- 用户发送消息后,立即插入自己的消息和一条空的 assistant 占位消息。
- 每解析到一段 delta.content,就追加到占位消息内容。
- 为“停止生成”按钮调用 controller.abort(),并在 finally 中清理控制器。
- 解析失败时保留已生成文本,并显示可重试的错误状态。
第三步:处理生产环境常见问题
流式接口需要处理断网、429 限流、上游 5xx、超时和用户主动取消。服务端应将上游状态码转换为稳定的前端错误格式,不要把 API Key、完整上游响应或内部堆栈返回给客户端。为单个用户配置速率限制和消息长度限制,避免恶意请求放大成本。
聊天记录较长时,不能无限制地把全部 messages 发送给模型。生产中可保留 system prompt、最近若干轮对话和一段摘要;同时按模型的上下文窗口计算 token 预算。还应把 model、首 token 时间、总耗时、输入输出 token 与错误码写入日志,这些指标能帮助你比较 Claude 与 GPT 模型在 59API 上的成本和响应表现。
最后,使用真实网络环境测试:确认首段内容能迅速显示、停止按钮确实中断请求、刷新页面不会泄露密钥,并检查反向代理没有缓存 SSE。完成这些环节后,React 前端就拥有可扩展的流式聊天基础。需要以较低成本快速接入多种主流模型时,可以注册 59API 并先用小流量验证适合自己业务的模型组合。
शुरू करने के लिए तैयार?
कुछ ही मिनटों में Claude और GPT जोड़ें, सबसे कम कीमत पर। साइन अप करें और API key पाएं।
मुफ़्त साइन अप