症状
本篇调试指南针对“Express PayloadTooLargeError — 请求体超出限制”。内容涵盖可观察的症状、可复现的诊断路径、根本原因、具体修复方式,以及如何验证修复并防止回归。
可观察到的症状包括:
- API 仅对较大提交返回 413 “request entity too large”
- 较小的 JSON 成功,稍大的对象却返回 413
- 错误来自 body-parser,而非你的路由处理器
诊断
先在隔离环境中复现故障,再按顺序执行以下检查,逐步缩小范围。
步骤 1
curl -i -X POST https://api.example.com/items -H 'Content-Type: application/json' --data-binary @large.json
若 413 带有代理的 Server 头则是代理限制;若由 body-parser 记录则是应用限制。
步骤 2
wc -c large.json
与配置的限制对比;应略高于真实最大值,而不是设为无限。
步骤 3
grep -rn "bodyParser\|express.json" src/ | grep -i limit
配置的限制(或缺失时默认的 100kb)解释了阈值从何而来。
常见诱因(按出现频率排序):
- 默认 100kb 的 JSON 限制小于正在发送的请求
- 反向代理也限制请求体大小,在 Express 收到前就返回 413
- 把 multipart 或大文本负载错误地送进了 JSON 解析器
根因
当流式请求体超过配置限制时,body-parser 立即拒绝并抛出 PayloadTooLargeError,早于处理器执行。前置代理还可能施加更小的第二层限制。
修复
为每个解析器设置明确且有界的限制(如 express.json({ limit: “1mb” })),把大文件上传改走流式/multipart 处理器,并把代理的 client_max_body_size 对齐为同一数值。
注意:不设上限的请求体是拒绝服务的入口,务必设置上限并校验 Content-Length。
import express from 'express';
const app = express();
app.use(express.json({ limit: '1mb' }));
app.use(express.urlencoded({ extended: true, limit: '1mb' }));
// 413 arrives before this handler when the limit is exceeded.
app.post('/items', (req, res) => res.json({ received: req.body }));
app.use((err, _req, res, _next) => {
if (err.type === 'entity.too.large') return res.status(413).json({ error: 'payload too large' });
res.status(500).json({ error: 'internal error' });
});
验证
先提交略小于新限制的负载确认 200,再提交略超限制的负载,确认返回受控的 413 与友好提示,而非崩溃。
修复后补充一条回归测试,复现原始症状,防止问题再次出现。
这类故障通常是环境问题而非纯逻辑错误,因此在缺陷记录中应写明完整命令、环境变量与工作目录。请用最小的脚本复现,待最小用例清楚后再扩大范围。为这类故障准备一份简短的排查清单,能显著减少下次排障时间。