要用 fetch 实现流式读取并完美对接 OpenAI 或 DeepSeek 等大模型 Chat 接口,核心是正确处理 SSE 或 chunked 编码响应流,在 Vue3 中实时更新 UI;需设置 stream: true、Content-Type: text/event-stream,禁用代理缓冲,用 Response.body.getReader() 解析 data: 块并提取 delta.content,配合响应式 ref 和防抖追加内容,异常时调用 reader.cancel()。

要用 fetch 实现流式读取并完美对接 OpenAI 或 DeepSeek 这类大模型的 Chat 接口,核心在于正确处理 Server-Sent Events(SSE) 或 分块传输编码(chunked encoding) 的响应流,同时在 Vue3 等前端框架中实时更新 UI。这不是简单发个请求就能完成的事,关键在“边收边吐”的控制逻辑。
确保后端返回标准流式格式
OpenAI 官方 API(如 /v1/chat/completions)和 DeepSeek v3.2 think、DeepSeek-v4 等主流模型接口,都支持 stream: true 参数。启用后,响应体是多个以 data: { ... } 开头的纯文本块,每块含一个 delta.content 字段,例如:
data: {"choices":[{"delta":{"content":"今"},"index":0}]}data: {"choices":[{"delta":{"content":"天"},"index":0}]}data: {"choices":[{"delta":{"content":"天"},"index":0}]}
注意:必须设置 Content-Type: text/event-stream,且响应不能被中间代理(如 Nginx)缓冲或 gzip 压缩——否则前端收不到实时 chunk。
用 Fetch + ReadableStream 解析 SSE 流
现代浏览器支持 Response.body.getReader(),这是比 EventSource 更可控的方式,尤其适合 Vue3 组合式 API 中手动管理状态:
- 发起 fetch 时带上
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'deepseek-chat', messages, stream: true }) } - 拿到
response后,检查response.ok和response.headers.get('content-type')?.includes('event-stream') - 调用
const reader = response.body.getReader(),然后循环reader.read()获取{ done, value } - 对每个
value(Uint8Array),转成字符串,按\n\n拆分,再逐行识别data:行,JSON.parse其内容提取delta.content - 把新内容追加到当前消息的
content字段,触发视图更新
Vue3 中避免 UI 卡顿与状态错乱
流式渲染不是“等全量回来再显示”,而是持续 patch。需注意三点:
- 消息对象必须是响应式引用(如
ref({ role: 'assistant', content: '' })),不能用普通字符串拼接后一次性赋值 - 每次追加内容前,先做防抖判断:
if (chunk && typeof chunk === 'string' && chunk.trim()),过滤空行、data: [DONE]等控制帧 - 异常中断时(如网络断开、token 耗尽),要主动调用
reader.cancel()并清理 loading 状态,防止 pending 一直挂起
兼容性兜底与错误处理
部分旧环境或代理不支持流式响应,可加一层 fallback:
- 设超时(如 8s),若未收到首个 data 块,降级为非流式请求(
stream: false),但提示用户“正在生成,请稍候” - 捕获
TypeError: Failed to fetch或AbortError,统一展示重试按钮 - 对 DeepSeek 接口,注意其部分版本(如 v3.2 think)可能返回
delta.tool_calls,需额外解析 function calling 场景



















