如何修复 Nginx 413 Request Entity Too Large:完整指南

当 Nginx 返回 413 Request Entity Too Large 时,意味着服务器拒绝了请求,因为客户端发送的请求体超过了 Nginx 配置允许接收的最大值。上传或 POST 请求根本到不了你的应用 — Nginx 在入口处就把它挡了下来。

这个上限由一条指令控制:client_max_body_size。Nginx 开箱即用的默认值是 1 兆字节,对普通表单提交和 API 调用够用,但对媒体上传、主题压缩包、数据库导入或大型 JSON 负载来说远远不够。好消息是修复几乎总是一行配置的事 — 前提是你要同时调整整条调用链上的限制:Nginx、PHP 和你的应用。

什么是 Nginx 413 Request Entity Too Large?

HTTP 413 是一个客户端错误状态码,在 RFC 9110 中定义为 413 Content Too Large(Nginx 仍沿用旧的 reason phrase Request Entity Too Large)。当传入的请求体 — 包括表单数据、文件上传或 JSON — 超过 client_max_body_size 的值时,Nginx 就会返回它。关键在于,Nginx 是在缓冲请求时检查这个大小的,所以 413 可能在请求到达 PHP-FPM、Node.js 或上游应用之前就已返回。

因为这个检查发生在 Nginx 层,你通常会看到一段纯 413 页面或空白响应,而不是应用层错误。在 Nginx 错误日志中,出问题的请求会带着 client intended to send too large body 的消息出现,这正是该问题的决定性特征。

常见原因

分步修复指南

按顺序执行以下六个步骤。它们从定位正确的文件开始,经过在合适的作用域调大限制,再到对齐 PHP 与反向代理,最后验证结果。

第 1 步:定位生效的 Nginx 配置文件

在修改任何东西之前,先找到 Nginx 实际加载的文件。配置可能位于 nginx.confsites-enabled 下的站点文件,或 conf.d 的 include 中。编辑错误的文件是修复"不生效"最常见的原因。

# 打印完整合并后的配置并搜索该指令
sudo nginx -T 2>/dev/null | grep -n client_max_body_size

# 常见需要检查的位置
ls -la /etc/nginx/nginx.conf
ls -la /etc/nginx/conf.d/
ls -la /etc/nginx/sites-enabled/

第 2 步:在 http 块中调大 client_max_body_size

打开 nginx.conf,在 http 块内设置该指令,使其全局生效。选择一个能覆盖你最大预期上传的值。

# /etc/nginx/nginx.conf
http {
    # 允许最大 64 MB 的上传
    client_max_body_size 64m;

    # ... 其余 http 配置
}

64m 能覆盖大多数媒体上传。视频或备份可用 128m 或更大。生产环境不要设为 0(无限制)— 那样你将没有任何防御恶意请求的能力,可能耗尽内存或塞满磁盘。

第 3 步:按 server 或 location 粒度设置

为了更精细的控制,可仅在发生上传的地方(如专用的上传 location)设置 client_max_body_size。location 级别的值会覆盖 http 级别,因此你可以保留较小的全局默认值,同时仅在单个端点允许大请求体。

server {
    listen 80;
    server_name example.com;

    # 本站点全局默认
    client_max_body_size 32m;

    location /upload {
        # 仅此端点接收大文件
        client_max_body_size 256m;

        proxy_pass http://backend;
    }
}

第 4 步:对齐 PHP 上传限制

如果 Nginx 把请求转发给 PHP-FPM,PHP 会执行自己的限制。同时调大 upload_max_filesizepost_max_size,使其大于等于 Nginx 限制。post_max_size 必须是两者中较大的,因为它覆盖整个 POST 体,而非单个文件。

# 查找 FPM 进程实际加载的 php.ini
php -i | grep "Loaded Configuration File"

# 编辑 FPM 的 ini(CLI 与 FPM 使用不同文件)
sudo nano /etc/php/8.2/fpm/php.ini
; /etc/php/8.2/fpm/php.ini
upload_max_filesize = 64M
post_max_size = 128M
memory_limit = 256M
max_execution_time = 300
# 应用 PHP 改动
sudo systemctl restart php8.2-fpm

第 5 步:配置反向代理转发大请求体

当 Nginx 位于另一个 Nginx 或应用服务器前面时,做代理的服务器会应用自己的 client_max_body_size。如果只调大了后端,前端代理仍会返回 413。在代理上设置该限制并放行请求体。

# 前端代理服务器
server {
    listen 443 ssl;
    server_name example.com;

    # 与后端容量匹配
    client_max_body_size 64m;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_request_buffering on;
    }
}

第 6 步:测试配置并重载 Nginx

重载前务必校验,避免一个拼写错误让整站下线。然后平滑重载并用实际上传验证。

# 校验语法
sudo nginx -t

# 不中断连接的重载
sudo nginx -s reload

# 验证大 POST 是否成功(替换为你的端点)
curl -v -X POST -F "file=@large-file.zip" https://example.com/upload

预期返回 HTTP/1.1 200 OK。若仍看到 413,回头检查你编辑的是否是 Nginx 实际加载的文件(第 1 步),以及是否有更具体的 serverlocation 块覆盖了你的值。

Nginx 诊断命令

这些命令可帮你确认运行中的上限并复现 413,从而判断是哪一层在拦截请求。

# 显示已加载配置中生效的 client_max_body_size
sudo nginx -T 2>/dev/null | grep -i client_max_body_size

# 确认 Nginx 使用的是哪个配置路径
sudo nginx -V 2>&1 | grep -o '\-\-conf-path=[^ ]*'

# 触发上传时实时观察错误日志
sudo tail -f /var/log/nginx/error.log

# 用超过默认 1 MB 的请求体复现 413
curl -v -X POST -d "$(head -c 2000000 /dev/zero | tr '\0' 'a')" \
     -H "Content-Type: application/octet-stream" \
     http://localhost/upload

# 从 CLI 查看 PHP 的生效限制
php -i | grep -E "upload_max_filesize|post_max_size|memory_limit"

你应在错误日志中看到 client intended to send too large body 出现在 413 的同一时刻,这确认了是 Nginx — 而非 PHP — 在拦截请求。如果相反,PHP 日志报告了 PostExceededSize,则需要在 php.ini 中调大限制。

快速参考表

症状 原因 修复
任何超过 1 MB 的上传都 413 默认 client_max_body_size1m 在 http 块设置 client_max_body_size 64m
仅 WordPress 媒体上传 413 PHP upload_max_filesize 小于 Nginx 限制 在 php.ini 调大 upload_max_filesizepost_max_size,重启 PHP-FPM
反向代理后出现 413 前端代理保留小默认值 在代理服务器上也设置 client_max_body_size
JSON API 413 但表单正常 JSON 体超过 1 MB 默认值 为 API location 调大 client_max_body_size
日志:client intended to send too large body Nginx 在缓冲阶段拦截了请求 nginx -T 确认并调大限制
PHP 日志报告 PostExceededSize PHP 上限低于 Nginx 上限 设置 post_max_size 大于 upload_max_filesize
进阶提示:如果你在 Nginx 前面使用 Cloudflare,请记住 Cloudflare 也会按套餐限制最大上传大小(免费版为 100 MB)。来自 Cloudflare 的 413 不会出现在你的 Nginx 日志中,因此请检查响应头 — 带有 Server: cloudflare 的响应指向的是 CDN 层。

常见问题

Nginx 默认的 client_max_body_size 是多少?

默认为 1 兆字节(1m)。除非你调大该指令,否则任何超过 1 兆字节的请求体都会被以 413 拒绝。这个默认值很安全,但对几乎所有现代上传场景来说都太小。

应该把 client_max_body_size 设为 0 以无限制吗?

可以 — 设为 0 会禁用该检查 — 但生产环境不推荐。没有上限时,单个超大的请求就可能耗尽内存或用缓冲的请求体塞满磁盘。请根据你最大的合法上传选择一个明确的额度。

调大 client_max_body_size 后为什么还是 413?

最常见的原因是编辑了错误的文件(用 nginx -T 核对)、更具体的 serverlocation 块覆盖了 http 级别的值,或者前端反向代理仍使用 1 MB 默认值。用 nginx -s reload 重载,并用上面的诊断命令确认生效值。

client_max_body_size 会影响 GET 请求吗?

client_max_body_size 适用于任何带请求体的请求。GET 请求通常不带请求体,所以该指令很少影响它们,但它确实作用于 POST、PUT 和 PATCH — 也就是上传所用的方法。带有大请求体的 GET 很少见,通常意味着客户端行为异常。

总结

413 Request Entity Too Large 一旦你理解了由单条指令 client_max_body_size 控制阈值,就是最容易解决的 Nginx 问题之一。把它调大到符合你实际上传需求的值,对齐 PHP 的 upload_max_filesizepost_max_size,并记得在路径上的任何反向代理上设置相同的限制。用 nginx -t 校验、平滑重载、用 curl 确认。养成这四个习惯,413 就不再是反复发生的事故,而是一次性的配置任务。

相关指南