30 秒自检:确认是不是这个问题
错误堆栈出现:
Body exceeded 1mb limitRequest Entity Too LargePayload too large- HTTP 413
且发生在 Server Action 调用时。
最短处理路径
Step 1:判断文件大小
| 大小 | 推荐方案 |
|---|---|
| < 1MB | Server Action 默认即可 |
| 1-4MB | 调 bodySizeLimit |
| 4-50MB | Route Handler + streaming |
| > 50MB | Presigned URL |
Step 2:调 bodySizeLimit(小文件场景)
next.config.js:
module.exports = {
experimental: {
serverActions: {
bodySizeLimit: '4mb',
},
},
};
注意:Vercel 平台层 4.5MB 限制,设到 100mb 也没用。
Step 3:用 Presigned URL(大文件场景)
最佳方案。步骤:
// Server Action: 只返回 URL
'use server';
export async function getUploadUrl(filename: string) {
const presignedUrl = await s3Client.getSignedUrl('putObject', {
Bucket: 'my-bucket',
Key: filename,
Expires: 600,
});
return { url: presignedUrl, key: filename };
}
// 客户端
'use client';
const onUpload = async (file: File) => {
const { url, key } = await getUploadUrl(file.name);
await fetch(url, {
method: 'PUT',
body: file,
headers: { 'Content-Type': file.type },
});
await registerUpload({ key });
};
绝大多数 S3 兼容存储(S3 / R2 / Supabase Storage / Spaces)都支持 Presigned URL。
Step 4:Route Handler 流式处理(中等文件)
// app/api/upload/route.ts
export async function POST(req: Request) {
const reader = req.body!.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
// 流式写入存储
await writeChunkToStorage(value);
}
return Response.json({ ok: true });
}
Request.body.getReader() 让你逐 chunk 处理,不会一次性收完。
Step 5:分块上传
如果文件超过 50MB,且必须经过 Server,用 multipart upload:
- Client 把文件切成 5MB chunk
- 每 chunk 用 Presigned URL 单独上传
- 上传完后调 Server Action 合并
S3 的 multipart upload API 内置这套机制。
原因分析
Next.js Server Action 设计上是「同步函数调用」隐喻,处理 form 数据 + 小响应。大文件传输不是 Server Action 的设计目标。Vercel 平台层 4.5MB 限制是 Lambda 100MB 限制减去 base64 编码膨胀(base64 比二进制大 33%)。
怎么判断是 Next.js 限制还是 Vercel 平台限制?
现象:本地 1GB 文件能上传,Vercel 4.5MB 就 413
Vercel Function payload 限制。本地 Next.js dev server 没有这个限制,所以 local 测试无问题。必须用 Presigned URL。
现象:bodySizeLimit 设了 10mb 还是 413
Vercel 平台层先卡 4.5MB,Next.js 设置无效。要么换 Enterprise(100MB),要么改方案。
现象:Cloudflare Workers 限制更严
Cloudflare Workers Free 单次请求 1MB,Pro 100MB。Next.js + Cloudflare 部署的文件上传必须 Presigned URL。
专业上传服务
考虑用专业上传 SDK:
- Uploadcare - 客户端 SDK,签名走你的服务器
- UploadThing - Next.js 专用上传服务
- Bytescale - 类似服务
这些服务把 Presigned URL + 分块 + 进度 + retry 打包,月 $0-50 起步。
跨地区访问 S3 / R2 Dashboard
排查上传问题时要在 S3 / R2 Dashboard 看实际上传情况、CORS 配置。国内访问 AWS Console、Cloudflare R2 Dashboard 偶尔加载缓慢,一条海外服务跑 GitHub Actions / Cloudflare 的稳定线路能让 Dashboard 顺畅、排查更快。