NextJS API作为中间层转发带文件的FormData到后端的问题
核心原因
NextJS API路由默认开启的内置请求体解析器不支持处理multipart/form-data类型的文件上传请求,会破坏原始FormData结构,同时直接将普通对象作为fetch的body参数也不符合后端接收FormData格式的要求。
解决方案
场景1:不需要修改请求内容,直接透传(推荐,性能最优)
无需额外依赖,直接禁用内置请求体解析后将原始请求流转发给后端即可:
import { getAccessToken, withApiAuthRequired } from "@auth0/nextjs-auth0"; export default withApiAuthRequired(async function brands(req, res) { const { accessToken } = await getAccessToken(req, res, {}); try { const upstreamResponse = await fetch("http://localhost:5000/brands", { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, // 透传原请求的Content-Type,包含multipart格式的边界分隔符信息 "Content-Type": req.headers["content-type"], }, // 直接传入原始请求作为body,无需解析重打包 body: req, }); const result = await upstreamResponse.json(); // 透传上游返回的状态码和响应内容 res.status(upstreamResponse.status).json(result); } catch (err) { res.status(500).json({ error: "请求转发失败" }); } }); // 禁用NextJS默认的请求体解析 export const config = { api: { bodyParser: false, }, };
场景2:需要修改FormData字段后再转发
如果需要在转发前增删修改请求字段,可以先解析原始FormData,调整后重新构建FormData再转发,需要先安装依赖:npm install formidable form-data
对应API代码:
import { getAccessToken, withApiAuthRequired } from "@auth0/nextjs-auth0"; import formidable from "formidable"; import FormData from "form-data"; import fs from "fs"; export default withApiAuthRequired(async function brands(req, res) { const { accessToken } = await getAccessToken(req, res, {}); // 解析原始FormData const form = formidable({}); const [fields, files] = await form.parse(req); // 构建新的FormData const formData = new FormData(); // 追加普通字段,可根据需求修改字段值 formData.append("title", fields.title[0]); formData.append("slug", fields.slug[0]); formData.append("bio", fields.bio[0]); // 追加文件字段 formData.append("logo", fs.createReadStream(files.logo[0].filepath), files.logo[0].originalFilename); try { const upstreamResponse = await fetch("http://localhost:5000/brands", { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, // 自动生成带边界的FormData请求头 ...formData.getHeaders(), }, body: formData, }); const result = await upstreamResponse.json(); res.status(upstreamResponse.status).json(result); } catch (err) { res.status(500).json({ error: "请求处理失败" }); } }); // 禁用默认请求体解析 export const config = { api: { bodyParser: false, }, };
注意事项
- 如果使用NextJS 13+ App Router的路由处理器,默认不会解析请求体,可直接读取
request.body作为流透传,无需额外配置禁用bodyParser。 - 透传multipart请求时不可手动指定
Content-Type为固定值,必须携带自动生成的边界信息,否则后端无法正常解析FormData。
内容的提问来源于stack exchange,提问作者elijah
相关产品推荐
相关产品推荐

