如何在Vercel Serverless函数中实现流式响应?本地正常部署失效
解决Vercel Serverless Functions部署后流式响应失效的问题
你的核心问题是Vercel Serverless Functions默认会缓冲所有响应内容,直到函数执行完毕才一次性返回,导致流式打字效果失效。以下是具体修复方案:
关键修复步骤
- 设置Vercel专属头部禁用响应缓冲
- 配置正确的响应内容类型与缓存控制
- 修正流式写入逻辑,避免重复输出HTML结构
修改后的核心代码
const { Configuration, OpenAIApi } = require("openai"); const configuration = new Configuration({ apiKey: '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', // 请替换为你自己的OpenAI API密钥 }); const openai = new OpenAIApi(configuration); export default async function handler(req, res) { // 1. 禁用Vercel响应缓冲,开启流式传输 res.setHeader('X-Vercel-Buffer-Response', 'false'); // 2. 配置响应头:指定内容类型,禁用缓存 res.setHeader('Content-Type', 'text/html; charset=utf-8'); res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); res.setHeader('Pragma', 'no-cache'); res.setHeader('Expires', '0'); // 3. 先输出HTML基础结构,仅执行一次 res.write("<!DOCTYPE html><html><body>"); try { const completion = await openai.createChatCompletion({ model: "gpt-3.5-turbo", stream: true, messages: [ { role: "system", content: "You are an AI." }, { role: "user", content: "how are you?" } ], }, { responseType: 'stream' }); completion.data.on('data', data => { const lines = data.toString().split('\n').filter(line => line.trim() !== ''); for (const line of lines) { const message = line.replace(/^data: /, ''); if (message === '[DONE]') { // 4. 流结束时关闭HTML标签并结束响应 res.write("</body></html>"); res.end(); return; } try { const parsed = JSON.parse(message); const content = parsed.choices[0].delta.content; if (content) { // 流式写入内容 res.write(content); } } catch (error) { console.error('解析流消息失败', message, error); } } }); // 监听流错误事件,确保异常时正确结束响应 completion.data.on('error', (err) => { console.error('OpenAI流请求错误', err); res.write('<p>请求发生错误,请重试</p></body></html>'); res.end(); }); } catch (error) { console.error('OpenAI请求出错', error); res.write('<p>请求发生错误,请重试</p></body></html>'); res.end(); } }
修复说明
- X-Vercel-Buffer-Response:这是Vercel专属响应头,设置为
false会强制Serverless Functions实时发送响应内容,而非缓冲到执行结束。 - 响应头配置:明确内容类型为HTML并禁用缓存,避免浏览器或CDN中间节点缓冲内容,确保流式内容实时到达前端。
- HTML结构输出:将基础HTML标签放在函数最开始仅输出一次,避免在每个data事件中重复写入,导致页面结构混乱。
- 错误处理:添加流错误监听与全局异常捕获,确保异常情况下能正确关闭HTML标签并结束响应,避免连接挂起。
内容的提问来源于stack exchange,提问作者And Bast
相关产品推荐
相关产品推荐

