如何让Cloudflare Worker将OpenAI响应流式返回至前端?
解决Cloudflare Worker流式转发OpenAI响应的问题
问题分析
你的代码当前会等待OpenAI的完整响应返回后才向前端输出数据,核心原因是:
- 在返回Response之前就完成了整个
for await...of循环,把所有数据写入TransformStream,导致前端必须等所有数据处理完才能收到响应 - 未利用Cloudflare Worker的
ctx.waitUntil方法,无法确保Worker在返回响应后仍能后台处理流数据
修复后的Worker代码
export default { async fetch(request, env, ctx) { const openai = new OpenAI({ apiKey: "##-#######" }); // 请求OpenAI API获取流式响应(无需await整个结果,直接拿到AsyncIterable) const stream = openai.chat.completions.create({ model: "gpt-3.5-turbo", messages: [{ role: "user", content: "Tell me a story using 2000 chars." }], stream: true }, { responseType: "stream" }); // 创建TransformStream处理流式数据 const transformStream = new TransformStream({ async transform(chunk, controller) { // 提取OpenAI返回的内容片段 const content = chunk.choices[0]?.delta?.content || ""; if (content) { // 将内容编码后发送到前端 controller.enqueue(new TextEncoder().encode(content)); } } }); // 用waitUntil确保Worker返回响应后继续后台处理流转发 ctx.waitUntil( (async () => { for await (const part of stream) { await transformStream.writable.getWriter().write(part); } await transformStream.writable.getWriter().close(); })() ); // 立即返回流式响应,前端可开始接收分块数据 return new Response(transformStream.readable, { headers: { 'Content-Type': 'text/plain; charset=utf-8', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept', 'Transfer-Encoding': 'chunked', 'Cache-Control': 'no-cache' // 禁用缓存,保证流式传输生效 } }); } };
关键改动说明
- 提前返回Response:不再等待所有流数据处理完毕,立即返回包含
transformStream.readable的Response,让前端能马上开始接收分块数据 - 使用
ctx.waitUntil:告知Cloudflare Worker在返回响应后继续后台处理流的转发,避免Worker提前终止导致流中断 - 规范处理流数据:用TransformStream的
transform方法处理每个chunk,避免手动管理writer的背压问题 - 添加
Cache-Control头:防止中间缓存(如Cloudflare CDN)将流式响应缓存为完整内容,确保分块传输生效
前端代码优化(可选)
前端代码基础逻辑没问题,可优化解码逻辑避免字符乱码:
const onSubmit = async (data) => { try { const response = await fetch('CLOUDFLARE_END_POINT'); if (!response.body) { console.error('浏览器不支持流式响应或服务器未返回流'); return; } const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); let receivedText = ''; while (true) { const { done, value } = await reader.read(); if (done) { console.log('流传输完成'); break; } // 解码当前chunk并拼接,避免跨chunk的字符乱码 receivedText += decoder.decode(value, { stream: true }); console.log(receivedText); // 这里可将receivedText渲染到页面 } } catch (error) { console.error('请求数据出错:', error); } };
前端优化点
- 复用同一个
TextDecoder实例,使用{ stream: true }选项确保跨chunk的多字节字符正确解码 - 拼接已接收文本,方便直接渲染到页面
内容的提问来源于stack exchange,提问作者allegutta
相关产品推荐
相关产品推荐

