网站出现413 Request Entity Too Large怎么办?上传限制排查

后台上传一张高清图,或者用户提交一个附件,页面直接返回"413 Request Entity Too Large"。这个错误很直白:请求体(body)太大了,超出了服务器或中间环节允许的上限。它经常出现在用户上传大文件、提交长表单、走 API 传大 JSON 的场景。

413 的麻烦之处在于"限制可能藏在好几层":Nginx 有一层、PHP 有一层、后端框架自己还有一层,任何一层卡住都会返回 413,而且报错信息可能只暴露其中一层。这篇文章把这几层限制按顺序讲清楚,告诉你每层怎么查、怎么调,以及调大限制时有哪些安全风险。读完你能快速定位是哪一层在拦,并做出合理的调整,而不是盲目把所有值往大了改。

一、413 是哪一层拦的

一个上传请求通常会经过这些环节,每层都可能有大小限制:

环节 相关限制 默认常见值
客户端/浏览器 一般无硬限制,受表单配置影响 —
CDN / WAF 请求体大小限制 视产品配置
Nginx client_max_body_size 1 MB
PHP-FPM post_max_size / upload_max_filesize 8M / 2M
后端框架 各自的上传/请求体限制 视框架
应用逻辑 业务自己的文件大小校验 视业务

Nginx 的 client_max_body_size 默认是 1MB,这是最常被忽略的一层。很多人只在 PHP 里把 upload_max_filesize 调大了,结果发现还是 413,就是因为 Nginx 这层没改。

二、第一步:确认是不是 Nginx 拦的

Nginx 返回 413 时,错误日志里会有明确记录。

# 看错误日志里的 413 相关记录
sudo grep -i 'client intended to send too large body' /var/log/nginx/error.log | tail

# 更直接:看访问日志里 413 的请求
sudo awk '$9 == 413 {print $9, $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

如果看到 client intended to send too large body: xxx bytes,基本可以确认是 Nginx 的 client_max_body_size 在拦。

调整方式(全局或站点级都可以,视需求选择):

# 方式一:http 段全局设置(影响所有站点)
http {
    client_max_body_size 50m;
    # ...
}

# 方式二:只在需要上传的 server 或 location 单独放开(推荐,影响面小)
server {
    listen 443 ssl http2;
    server_name example.com;

    location /upload/ {
        client_max_body_size 100m;
        proxy_pass http://backend;
    }
}

单纯调 client_max_body_size 还可能导致另一种问题:如果请求体超过 Nginx 缓冲区又没配置临时目录,Nginx 会写临时文件,client_body_temp_path 所在分区空间不足也会失败。一般默认目录够用,大文件场景可以确认一下:

client_body_temp_path /var/cache/nginx/client_temp;   # http 段可选配置
client_body_buffer_size 128k;                          # 请求体缓冲区

改完配置一定要先测试语法再平滑重载:

sudo nginx -t && sudo systemctl reload nginx

三、第二步:确认 PHP 的限制

如果 Nginx 已经放开,页面还是报错(可能这次是 PHP 层面的报错而非 413),就要看 PHP 的两个关键配置。

# 查看 PHP 配置文件的路径(不同系统、不同 SAPI 位置不同)
php -i | grep -i 'Loaded Configuration File'
php -i | grep -iE 'post_max_size|upload_max_filesize|memory_limit|max_execution_time'

# 也可用 phpinfo() 页面查看,或直接看配置文件
# Debian/Ubuntu 常见:/etc/php/8.1/fpm/php.ini
# RHEL/CentOS/Rocky 常见:/etc/php.ini

三个参数各有分工,必须协调:

  • upload_max_filesize:单个上传文件的最大大小。
  • post_max_size:整个 POST 请求体(含所有字段和文件)的最大大小,必须 ≥ upload_max_filesize。如果表单里除了文件还有别的字段,post_max_size 要比文件上限更大一些。
  • memory_limit:PHP 进程可用内存,处理大文件时要留出余量,否则会内存不足。

典型配置(在 php.ini 里修改):

upload_max_filesize = 100M
post_max_size = 110M
memory_limit = 256M
max_execution_time = 300
max_input_time = 300

同时别忘了 PHP-FPM 池配置里的超时(/etc/php-fpm.d/www.conf 或 /etc/php/8.1/fpm/pool.d/www.conf):

request_terminate_timeout = 300

改完重启对应服务:

# Debian/Ubuntu(注意版本号)
sudo systemctl restart php8.1-fpm
# RHEL/CentOS/Rocky
sudo systemctl restart php-fpm

一个常见误区:只在 .htaccess 或 ini_set() 里改 upload_max_filesize 是无效的,因为这两个是 PHP_INI_PERDIR 级别,必须在 php.ini、httpd 配置或 .user.ini 里设置才能生效。post_max_size 同理。改错地方却不报错、不生效,特别容易误导排查。

四、第三步:确认后端框架与网关的限制

排除了 Nginx 和 PHP,还剩后端框架和中间网关。不同技术栈的限制点不同:

# Spring Boot(Java)常见请求体限制
# application.yml 或 properties
# spring.servlet.multipart.max-file-size=100MB
# spring.servlet.multipart.max-request-size=100MB
# 老版本用 spring.http.multipart.*

# Node.js(Express + multer)
# multer({ limits: { fileSize: 100 * 1024 * 1024 } })

# 若前面有云 WAF 或 API 网关,也有独立的请求体大小限制
# 需要到对应控制台查看并调整

这类限制在应用日志里通常有更明确的报错,比如 Java 的 MaxUploadSizeExceededException、Node 的 PayloadTooLargeError。看到这类错误就知道是框架层在拦,改框架配置即可。

排查顺序总结成一个原则:从外往里逐层确认。先 Nginx,再 PHP/应用运行时,再框架,最后网关。哪层报错对应哪层配置,避免一次改一堆、出了问题不知道是谁的锅。

前后端分离场景要特别注意

当 Nginx 只做反向代理、后端是自己的应用(Java、Go、Node 等)时,"Nginx 的 client_max_body_size"和"后端的请求体限制"是两道独立的门,必须都放开。常见情况是:把 Nginx 的 client_max_body_size 从 1m 调到 100m 后,413 依旧,因为后端框架自己的上限还是默认值。这时要看后端的报错日志,而不是盯着 Nginx。反过来,如果后端放开了但 Nginx 没放开,请求根本到不了后端,Nginx 直接返回 413,后端日志里连这条请求都看不到。判断方法很简单:如果 Nginx 的 access.log 里有这条请求且状态是 413,多半是 Nginx 拦的;如果后端日志里压根没有这次上传记录,也说明是前面某一层挡住了。理清"请求到底走到了哪一层",比盲目调参高效得多。

用真实文件做验证

改完配置不要只看设置值,要用一个真实文件验证。文件大小建议取"明显超过原限制、又低于新限制"的中间值,比如原来限制 1MB,你调到了 100MB,就用一个 30MB 左右的文件测试。测试时观察是上传成功、还是报 413、或者报其他错误(比如超时或内存不足),据此判断是"限制"问题还是"资源"问题。如果 30MB 能传、80MB 报 413,说明还有一层没放开;如果传到一半断掉,多半是超时或内存问题,要回到第三节调超时和 memory_limit。

五、放宽上传限制的安全风险

把上传限制调大很方便,但也打开了攻击面,需要权衡:

  • 磁盘打满风险。放开上传后,攻击者可以反复上传大文件消耗磁盘,导致服务不可用。要配合磁盘配额、上传频率限制和定期清理。
  • 大请求拖垮后端。超大请求体会占用内存和连接更久,慢速上传(slowloris 类)还可能耗尽连接数。Nginx 有 client_body_timeout、client_header_timeout 可缓解。
  • 恶意文件上传。限制放宽后,要更严格地校验文件类型、内容、扩展名,上传目录禁止执行脚本(location 里对上传目录 deny 执行 .php 等),并用独立域名或目录隔离。
  • 临时文件放大。Nginx 缓冲大请求体会写临时文件,PHP 也会用临时目录,要注意对应分区空间。

给几点落地建议:

# 上传目录禁止解析脚本(安全必备,Nginx 示例)
location ^~ /uploads/ {
    location ~ \.(php|php5|phtml|jsp|asp|aspx)$ {
        deny all;
    }
}

# 限制请求体读取超时,缓解慢速上传
client_body_timeout 60s;

风险提示:这些配置涉及行为改变,改动前建议备份原配置(例如 cp nginx.conf nginx.conf.bak),在低峰期操作,并准备好回滚。

六、一套完整的排查清单

步骤 检查点 命令/位置
1 Nginx 是否拦 error.log 的 too large body;client_max_body_size
2 PHP 上传上限 upload_max_filesize、post_max_size、memory_limit
3 PHP-FPM 超时 request_terminate_timeout
4 应用运行时 Java/Node/Go 各自的请求体限制
5 网关/WAF/CDN 控制台里的请求体大小设置
6 临时目录空间 df -h 看 Nginx/PHP 临时目录所在分区
7 安全加固 上传目录禁执行脚本、限制频率

改完每一层都要 nginx -t(Nginx)或重启对应服务(PHP/框架),并用一个刚好超过原限制、又低于新限制的文件做实际测试,确认生效。

常见问题

Q:Nginx 的 client_max_body_size 已经改成 100m,为什么还 413?
看 413 是不是其他层返回的。可能 PHP 的 post_max_size 太小,或框架自己有上限,也可能前面 CDN/WAF 拦的。逐层确认。

Q:post_max_size 和 upload_max_filesize 谁大谁小?
post_max_size 要 ≥ upload_max_filesize。因为整个 POST 请求还包含其他字段,通常建议 post_max_size 比文件上限大 10%-20%,留出余量。

Q:.htaccess 里改 upload_max_filesize 没用?
对,这两个参数是 PHP_INI_PERDIR 级别,只能改 php.ini、httpd 配置或 .user.ini(需 user_ini.filename 生效),.htaccess 和 ini_set() 里改无效。

Q:调大限制后出现超时?
上传大文件耗时长,要同步调大 max_execution_time、max_input_time、request_terminate_timeout 和 Nginx 的 client_body_timeout,几处超时要协调一致。

Q:413 会影响搜索引擎吗?
一般不影响爬虫抓取普通页面,但如果站点关键内容以 413 返回,会导致该页面抓取失败。同时,开放大文件上传要防被滥用作消耗带宽和磁盘的入口。

总结

413 表示请求体超过限制,限制可能藏在 CDN/WAF、Nginx、PHP、后端框架等多层,需要从外往里逐层确认。

Nginx 的 client_max_body_size 默认 1MB 是高频坑点,按需要在 location 粒度放开更安全;nginx -t 通过后再 reload。

PHP 侧要同时调 upload_max_filesize、post_max_size、memory_limit,并注意它们必须在 php.ini/.user.ini 里改,.htaccess 和 ini_set() 无效;post_max_size 要大于文件上限。

放宽限制会带来磁盘打满、慢速上传、恶意文件上传等风险,务必给上传目录禁止执行脚本、限制频率并做好清理。

改动涉及配置行为,操作前备份、低峰期执行、准备好回滚,并用实际大文件测试确认每一层都生效。