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

Next.js 13 API POST用Busboy流式传大文件遇req.pipe报错求助

解决Next.js API路由中Busboy流式文件上传的req.pipe is not a function问题

问题原因

在Next.js 13+的App Router中,API路由的req对象是Web Streams API的ReadableStream,而非Node.js原生Stream对象,因此没有pipe()方法。直接使用Readable.fromWeb(req.body)转换后,若未配置流式处理,Next.js会先将整个请求体加载到内存中,无法实现真正的大文件流式上传。

正确解决方案

1. 启用路由动态处理

在API路由文件顶部导出dynamic配置,强制Next.js以流式方式处理请求,避免缓存请求体:

export const dynamic = 'force-dynamic';

2. 完整实现代码

通过转换Web Stream为Node.js Stream,配合Busboy完成流式文件上传,同时确保等待处理完成后再返回响应:

import { Readable } from 'node:stream';
import { createWriteStream } from 'node:fs';
import { join } from 'node:path';
import { NextResponse } from 'next/server';
import busboy from 'busboy';

// 强制动态处理,保证请求体以流式传递
export const dynamic = 'force-dynamic';

export async function POST(req) {
  return new Promise((resolve, reject) => {
    // 将Web Headers对象转换为普通对象,适配Busboy要求
    const headers = Object.fromEntries(req.headers.entries());
    
    const bb = busboy({ headers });

    bb.on('file', (fieldname, fileStream, info) => {
      const { filename } = info;
      console.log(`开始上传文件: ${filename}`);
      
      // 流式写入本地文件
      const savePath = join(process.cwd(), 'public/uploads', filename);
      const writeStream = createWriteStream(savePath);
      
      fileStream.pipe(writeStream);
      
      writeStream.on('finish', () => {
        console.log(`文件 ${filename} 上传完成`);
      });
      
      writeStream.on('error', (err) => {
        console.error(`文件写入失败: ${err}`);
        reject(err);
      });
    });

    bb.on('finish', () => {
      resolve(NextResponse.json({ success: true, message: '所有文件上传完成' }));
    });

    bb.on('error', (err) => {
      console.error(`Busboy处理出错: ${err}`);
      reject(NextResponse.json({ success: false, error: err.message }, { status: 500 }));
    });

    // 转换Web Stream并传递给Busboy
    Readable.fromWeb(req.body).pipe(bb);
  });
}

关键细节说明

  • dynamic: 'force-dynamic':必须配置,否则Next.js会预读取整个请求体到内存,导致流式处理失效。
  • Headers转换:Next.js的req.headers是Web API的Headers对象,需用Object.fromEntries()转为普通对象才能被Busboy解析。
  • Promise包裹:流式处理为异步操作,需用Promise等待Busboy的finish事件触发后再返回响应,避免请求提前终止。
  • 流式写入:直接将Busboy返回的文件流pipe到本地写入流,实现边传边写,不会占用过多内存。

内容的提问来源于stack exchange,提问作者Jian Shang Quan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 01:33:16