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

如何在Next.js中启用Rewrite的文本流式响应?

Next.js Rewrite 无法传递流式响应的问题与解决方法

一、Next.js Rewrite 的核心差异

Next.js 默认的 Rewrite 配置是聚合式代理:它会先等待后端服务器完整返回整个响应内容,缓存后再转发给前端。这种行为破坏了流式响应的逐段输出特性,导致前端无法实时接收后端的流式数据——这就是直接调用后端端点正常,但用Rewrite转发就失效的原因。

二、实现流式响应转发的解决方案

要传递流式响应,不能用静态的 next.config.js Rewrite 配置,必须通过API Route 手动代理,因为API Route允许我们直接控制响应流的传递逻辑。

1. 创建代理API Route

根据你使用的Next.js路由模式,选择对应的实现方式:

(1)Pages Router 模式

在 pages/api/django/[...path].js 文件中编写代理逻辑:

export default async function handler(req, res) {
  const { path } = req.query;
  // 拼接后端目标地址
  const targetUrl = `http://127.0.0.1:8000/${path.join('/')}`;

  // 转发请求到后端,开启流式支持
  const backendResponse = await fetch(targetUrl, {
    method: req.method,
    headers: {
      ...req.headers,
      // 替换host头,避免后端的域名验证问题
      host: '127.0.0.1:8000',
    },
    body: req.body,
    // 禁用缓存,确保响应实时流式传递
    cache: 'no-store',
  });

  // 同步后端的响应状态码和头信息
  res.status(backendResponse.status);
  for (const [key, value] of backendResponse.headers.entries()) {
    res.setHeader(key, value);
  }

  // 流式传递响应体到前端
  const reader = backendResponse.body.getReader();
  const stream = new ReadableStream({
    async start(controller) {
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        controller.enqueue(value);
      }
      controller.close();
    },
  });

  // 完成流的管道传输
  await stream.pipeTo(res).catch(() => {});
}

(2)App Router 模式

在 app/api/django/[...path]/route.js 文件中编写代理逻辑:

// 处理GET请求
export async function GET(request, { params }) {
  const { path } = params;
  const targetUrl = `http://127.0.0.1:8000/${path.join('/')}`;

  const backendResponse = await fetch(targetUrl, {
    method: request.method,
    headers: {
      ...Object.fromEntries(request.headers),
      host: '127.0.0.1:8000',
    },
    cache: 'no-store',
  });

  // 直接返回后端的流式响应
  return new Response(backendResponse.body, {
    status: backendResponse.status,
    headers: backendResponse.headers,
  });
}

// 处理POST请求(如需支持其他方法,同理扩展)
export async function POST(request, { params }) {
  const { path } = params;
  const targetUrl = `http://127.0.0.1:8000/${path.join('/')}`;

  const body = await request.text();
  const backendResponse = await fetch(targetUrl, {
    method: 'POST',
    headers: {
      ...Object.fromEntries(request.headers),
      host: '127.0.0.1:8000',
    },
    body,
    cache: 'no-store',
  });

  return new Response(backendResponse.body, {
    status: backendResponse.status,
    headers: backendResponse.headers,
  });
}

2. 修改前端请求地址

把原来直接调用后端的请求地址,改成代理API的地址:

// 原代码:const response = await fetch(`http://127.0.0.1:8000/endpoint`, { ... });
// 修改后:
const response = await fetch(`/api/django/endpoint`, {
  method: 'GET',
  headers: headers,
});

// 原有的流式处理逻辑保持不变
let decoder = new TextDecoderStream();
if (!response.body) return;
const reader = response.body
  .pipeThrough(decoder)
  .getReader();

while (true) {
  setLoading(true);
  var {value, done} = await reader.read();
  
  if (done) {
    break;
  } else {
    tmpPromptResponse += value;
    if (currentchatId === chatId) {
      setMarkdownContent(tmpPromptResponse + "▌");
    }
  }
}

三、关键原理说明

API Route 绕过了Next.js Rewrite的默认缓存逻辑,直接将后端的响应流原封不动地转发给前端。通过设置 cache: 'no-store' 确保响应不会被中间层缓存,同时同步后端的响应头(如 Transfer-Encoding: chunked),保证前端能正确识别并处理流式数据。

内容的提问来源于stack exchange,提问作者Nathan Wang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 10:11:06