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

NextJS 13基于formidable的文件上传API报错:TypeError: req.on is not a function

解决Next.js 13 App Router中Formidable文件上传API的req.on is not a function错误

问题原因

Next.js 13 App Router的路由处理函数接收的req是NextRequest对象(基于Web Streams API),而非传统Pages Router中的Node.js原生IncomingMessage。Formidable默认依赖Node.js的事件流(req.on),直接传入NextRequest会导致方法不存在的错误。

解决方案

方法1:使用Formidable v3+的Web Streams支持

Formidable v3及以上版本支持直接处理Web Streams,无需转换为Node.js原生请求对象,步骤如下:

  1. 安装最新版Formidable:
npm install formidable@latest
  1. 修改app/api/uploadfile/route.ts代码:
import { IncomingForm } from "formidable";
import { type NextRequest } from "next/server";

export async function POST(req: NextRequest) {
  const form = new IncomingForm({ multiples: true });
  
  // 从NextRequest获取表单数据并解析
  const formData = await req.formData();
  const { fields, files } = await form.parse(formData);
  
  // 示例:打印上传内容
  console.log("上传字段:", fields);
  console.log("上传文件:", files);
  
  // 返回CKEditor5要求的响应格式
  return new Response(JSON.stringify({
    uploaded: true,
    url: "/uploads/" + (files.image as any)[0].name // 替换为实际文件访问路径
  }), { status: 200 });
}

方法2:兼容旧版Formidable(转换为Node.js原生请求)

如果需要使用Formidable v2或更低版本,需将NextRequest转换为Node.js原生请求对象:

import { IncomingForm } from "formidable";
import { type NextRequest } from "next/server";
import { Readable } from "stream";

export async function POST(req: NextRequest) {
  // 将NextRequest的Web Stream转换为Node.js Readable流
  const readable = Readable.from(req.body as AsyncIterable<Uint8Array>);
  // 模拟Node.js原生请求的必要方法
  const nodeReq = {
    ...req,
    readable,
    on: readable.on.bind(readable),
    pipe: readable.pipe.bind(readable),
  } as any;

  const form = new IncomingForm({ multiples: true });
  
  const { fields, files } = await new Promise((resolve, reject) => {
    form.parse(nodeReq, (err, fields, files) => {
      if (err) reject(err);
      else resolve({ fields, files });
    });
  });

  // 返回CKEditor5适配的响应
  return new Response(JSON.stringify({
    uploaded: true,
    url: "/uploads/" + (files.image as any)[0].name // 替换为实际存储后的访问URL
  }), { status: 200 });
}

关键注意事项

  • 请求方法:CKEditor5上传适配器默认使用POST方法,建议将API方法改为POST,避免额外配置。
  • 响应格式:CKEditor5要求响应必须包含uploaded(布尔值)和url(文件访问地址字符串)两个字段,否则会判定上传失败。
  • 文件存储:示例仅做解析演示,实际需将文件保存到本地或云存储服务,并返回对应的可访问URL。
  • TypeScript类型优化:避免使用any,可导入Formidable类型定义:import type { Fields, Files } from "formidable";

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 13:07:38