You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 13.4 API流异常:本地逐Token传输,生产环境一次性到达

问题分析与解决方案

核心原因

生产环境出现流一次性返回的问题,主要是以下两个常见因素:

  • 反向代理缓冲:如果你的Digital Ocean Droplet使用了Nginx等反向代理,默认会缓冲整个响应直到请求处理完成,再一次性发送给客户端,直接阻断了分块传输。
  • Next.js生产模式的响应缓冲:Next.js在生产环境下,Node.js Runtime的API路由可能默认启用响应缓冲,导致流数据被暂存而非即时推送。

解决方案

1. 为API路由添加正确的响应头

修改你的API路由代码,显式设置分块传输相关的响应头,告诉客户端和中间件不要缓冲数据:

// FILE: app/api/chat/route.js
export async function POST(request) {
    const stream = new ReadableStream({
        async start(controller) {
            const encoder = new TextEncoder();
            for (const word of ['This ', 'is ', 'a ', 'test.']) {
                await new Promise(r => setTimeout(r, 1000));
                const queue = encoder.encode(JSON.stringify({chunk: word}) + '\n'); // 加换行符,方便客户端解析
                controller.enqueue(queue);
            }
            controller.close();
        },
    });
    return new NextResponse(stream, {
        headers: {
            'Content-Type': 'application/json; charset=utf-8',
            'Transfer-Encoding': 'chunked',
            'Cache-Control': 'no-cache, no-store, must-revalidate',
            'Connection': 'keep-alive',
            'X-Content-Type-Options': 'nosniff',
        },
    });
}

注意:每个chunk后添加\n换行符,避免JSON拼接导致的格式问题,方便客户端按行解析。

2. 禁用反向代理(Nginx)的缓冲

如果你的Droplet用Nginx做反向代理,修改Nginx配置文件(通常路径为/etc/nginx/sites-available/your-site.conf),在对应location块中添加以下配置:

location /api/ {
    proxy_pass http://localhost:3000; # 替换为你的Next.js服务地址
    proxy_buffering off;
    proxy_cache off;
    proxy_set_header Connection '';
    chunked_transfer_encoding on;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

修改后重启Nginx生效:

sudo systemctl restart nginx

3. 切换到Edge Runtime(可选)

Next.js的Edge Runtime专为流式传输等场景优化,可避免Node.js Runtime的缓冲问题。在API路由顶部添加以下声明:

export const runtime = 'edge'; // 添加这一行

export async function POST(request) {
    // 原有流代码...
}

客户端代码优化(可选)

为了更稳定地解析分块数据,调整客户端代码处理换行分隔的chunk:

const response = await fetch(`/api/chat`, { method: 'POST' });
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';

while (true) {
    const {value, done} = await reader.read();
    if (done) {
        // 处理剩余的未完成数据
        if (buffer) console.log(JSON.parse(buffer));
        break;
    }
    buffer += decoder.decode(value);
    // 按换行分割处理每个完整chunk
    const lines = buffer.split('\n');
    buffer = lines.pop(); // 保留未完成的行
    for (const line of lines) {
        if (line) console.log(JSON.parse(line));
    }
}

内容的提问来源于stack exchange,提问作者Rafael Monteiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 20:13:05