如何从FastAPI向React流式传输LLM(Ollama)响应?
解决FastAPI + React流式传输LLM响应时的onopen错误
问题背景
用FastAPI对接Ollama做LLM服务,非流式请求能正常返回结果,但流式传输时,React端触发console.log("another error onopen"),无法接收流式数据;而FastAPI后端能正常打印每个流式片段。前端使用@microsoft/fetch-event-source处理SSE响应。
核心原因
- 后端返回的流不符合SSE规范:Server-Sent Events要求每个数据块必须以
data:前缀开头,且以\n\n结尾,否则前端无法识别为合法的SSE消息。 - 前端状态更新缺失:即使后端修复格式,前端也没有处理消息来更新界面显示。
- Content-Type判断过于严格:后端返回的
Content-Type可能带有charset后缀(如text/event-stream; charset=utf-8),前端严格匹配EventStreamContentType(即text/event-stream)会导致判断失败。
修复步骤
1. 修改FastAPI后端,输出符合SSE规范的流
修改stream_answer函数,将每个LLM返回的chunk包装成SSE格式:
def stream_answer(question): for chunk in chain.stream(question): print(chunk, end='', flush=True) # 包装为SSE标准格式 yield f"data: {chunk}\n\n"
2. 调整前端的Content-Type判断逻辑
在onopen回调中,用includes替代严格相等,兼容带charset的Content-Type:
async onopen(response) { console.log("onopen"); console.log(response); if ( response.ok && response.headers.get("content-type")?.includes(EventStreamContentType) ) { return; // 连接正常 } else if ( response.status >= 400 && response.status < 500 && response.status !== 429 ) { console.log("fatal error onopen"); } else { console.log("another error onopen"); } },
3. 前端添加流式数据的状态更新
在onmessage回调中,更新answer状态,实现实时显示:
onmessage(msg) { console.log("onmessage"); console.log(msg); if (msg.event === "FatalError") { throw new FatalError(msg.data); } // 累加流式片段到响应内容中 setAnswer(prev => prev + msg.data); },
验证
修改完成后,重新启动FastAPI和React服务:
- 后端会继续正常打印每个chunk;
- 前端点击按钮后,
onopen会进入正常分支,onmessage会逐个接收SSE消息,界面实时更新LLM响应内容。
内容的提问来源于stack exchange,提问作者Simon1
相关产品推荐
相关产品推荐

