
小文件能上传,大文件却报 413,调高源站限制后仍然失败。这种问题需要按上传链路定位:客户端、CDN、网关、Nginx 和应用,任何负责检查请求体的环节都可能拒绝上传。
本文针对 HTTP 文件上传接口。示例需替换为获授权的测试环境,不要直接向生产业务接口发送测试数据;本文没有执行生产环境上传测试。
413 说明请求内容超限,不能直接判断是哪一层
HTTP 413 表示服务端拒绝处理超过其愿意或能够接收大小的请求内容。服务端可能提前终止请求,因此上传进度停在中途也可能与大小限制有关。只有临时性限制才适合依据服务端给出的 Retry-After 再试;固定大小上限不会因重复提交自动消失。[1]
排查时记录失败 URL、请求方法、时间、文件字节数、表单字段、响应状态和请求标识。错误页面样式或 Server 响应头只能作为线索,中间代理可能改写它们。应结合边缘日志、源站入口日志和应用日志确认拒绝位置。
如果请求到达源站入口却没有进入应用,优先查网关和代理;如果源站没有记录,还需确认日志范围和采集完整性,不能单凭“没日志”就认定 CDN 拒绝。
限制比较的是整次请求,文件大小只是其中一部分
使用 multipart/form-data 时,请求体还包含边界、各部分头部和其他字段。curl 的 -F 会生成这种请求。[3] 多文件表单要计算整次请求,不能只看单个文件。
建议在测试环境用两个尺寸接近的文件确认成功与失败边界,再对照每层限制。测试文件内容、扩展名、认证方式和字段名要符合接口要求,否则文件类型拒绝、鉴权失败会干扰判断。
下面以 Linux/macOS Bash 与 curl 为例,仅向明确允许测试上传的端点执行。先准备一个不含敏感信息的小样本 sample.bin,file 是示例字段名:
URL='https://upload.example.com/api/upload-test'
curl --connect-timeout 10 --max-time 120 -sS \
-D upload.headers -o upload.response \
-w 'status=%{http_code} uploaded=%{size_upload}\n' \
-F 'file=@sample.bin' "$URL"命令中不自动重试、不自动跟随跳转;如果接口需要认证,应按其安全流程补充。不要把令牌写入交付文件或公开日志。size_upload 是本次实际发出的上传量,若服务端提前拒绝,它可能小于完整请求体大小。[3]
在得到明确授权、源站允许直连且证书验证成立时,可在同一条命令中加入以下选项做源站对照,URL 仍保留原域名:
--noproxy '*' --resolve upload.example.com:443:203.0.113.10
这是需要加入 curl 命令的参数片段,不能单独执行。示例 IP 必须替换;要求 CDN 专用认证或只允许 CDN 回源的源站可能无法直连。不要长期开放源站,也不要用 -k 掩盖证书错误。[3]
Nginx 要检查实际命中的配置范围
Nginx 的 client_max_body_size 控制请求体上限,可用于 http、server 和 location;官方默认值为 1m,实际部署可能已经覆盖。超过配置值会返回 413。client_body_buffer_size 控制读取缓冲,较大的请求体可能写入临时文件,调大它不能替代请求体上限。[2]
确认故障请求实际进入哪个 server 和 location,再修改已有上传路径对应的配置。以下只是一行示例,并非可直接替换的完整配置:
# 放在已确认的上传 location 中;数值需按业务评估 client_max_body_size 32m;
保留原有路由与安全规则,备份配置后小范围调整。Nginx 将大小设为 0 会关闭这项检查,不建议把它作为通用修复。适用 systemd 的部署可先检查再重载:[2]
sudo nginx -t && sudo systemctl reload nginx
容器或编排平台使用各自流程;失败时恢复原配置。提高限制前,还要评估临时存储容量、上传并发、超时和清理策略,避免把拒绝请求转化为资源耗尽。
应用层限制需要单独核对
源站代理放行后,应用或文件解析组件仍可能拒绝请求。检查框架的请求体限制、上传组件的单文件和多文件限制,以及业务规则。JSON 解析器的配置不一定控制 multipart 上传,必须找到处理该接口的组件。
PHP 部署尤其要同时看 upload_max_filesize 与 post_max_size:前者限制单个上传文件,后者限制 POST 数据总量,应大于前者。超过 post_max_size 时,$_POST 和 $_FILES 可能为空,未必呈现为同样的 413 页面。[4] 还需确认 Web 进程加载的是哪份配置,不能用命令行 PHP 的结果替代。
建议做一张限制清单:边缘/CDN、负载均衡或网关、代理、应用组件、业务接口,分别记录配置来源与可调整范围。某层存在不可调整的硬上限时,继续增大源站配置无法让请求通过该层。
HTTP 分块传输与应用分片上传要分清
HTTP/1.1 的 chunked transfer coding 把一次消息体分块传输,仍然属于同一次请求。[5] 因此不能把手工加入 Transfer-Encoding: chunked 当作绕过请求体限制的方案。不要伪造 Content-Length,或混用冲突的消息定界字段。
应用分片上传则需要客户端和服务端协议配合:把文件拆成多次独立请求,记录上传会话与片序号,再由服务端校验和合并。它是否适合当前业务,需要检查后端已有能力,不能只把前端文件切开就声称上传已完成。
采用分片前,至少设计这些约束:
每片连同协议开销都低于整条链路的有效上限;单文件总量仍受业务配额约束。
上传会话绑定用户,重复片可安全处理,续传不能覆盖其他用户的数据。
合并时校验片数量、顺序、总大小和完整性。
限制并发,并清理过期会话和未完成分片。
如改为对象存储直传,应使用权限受限、有效期短的上传授权,并核验目标存储的大小规则、跨域配置和完成校验。迁移上传入口时,保留必要的访问控制,不以永久暴露源站作为捷径。
修复后验证边界,并保留超限拒绝
在测试环境依次验证:业务允许的小文件、接近允许上限的文件、明确超限文件、多文件请求,以及中断后的清理或续传。允许范围内应成功,超限请求仍应有可理解的错误反馈。
如果提高限制后返回 504 或磁盘错误,说明遇到了另一个瓶颈,需要继续定位,不能视为上传已修好。发布前记录调整范围、回滚配置与资源监控项。
处理 413 的目标是让合法上传通过,同时保留大小、权限和资源保护。定位拒绝层,再决定调整上限还是更换上传协议,改动范围会更清楚。
官方参考资料
资料核验日期:2026-10-10。命令为示例,未在用户生产环境执行。
[1] IETF RFC 9110,第 15.5.14 节,413 Content Too Large。https://www.rfc-editor.org/rfc/rfc9110.html
[2] Nginx Core Module:client_max_body_size、client_body_buffer_size。https://nginx.org/en/docs/http/ngx_http_core_module.html
[3] curl 官方手册:--form、--resolve、--noproxy、--write-out。https://curl.se/docs/manpage.html
[4] PHP Core INI directives:post_max_size、upload_max_filesize。https://www.php.net/manual/en/ini.core.php
[5] IETF RFC 9112,第 7.1 节,Chunked Transfer Coding。https://www.rfc-editor.org/rfc/rfc9112.html