PUT请求大Payload被截断至8k致PHP解析失败排查求助
排查PUT请求体被截断至8k的问题
根据你描述的情况,1M的PUT请求体发送到PHP+Nginx的Docker应用A后被截断到8209字节,且日志无报错,确实是个棘手的问题。我整理了几个优先级较高的排查方向,你可以逐一验证:
1. 定位问题环节:Nginx是否收到完整请求?
首先要明确是Nginx没拿到完整请求体,还是PHP/FPM环节出了问题:
- 添加Nginx请求长度日志:修改你的
log_format timed,加入$request_length(记录整个请求的总字节数,包含header和body):
重启Nginx后,查看access.log里的log_format timed '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent $request_length $request_time "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';$request_length值:如果接近1M(约1048576字节),说明Nginx已收到完整请求,问题在PHP/FPM;如果只有8k左右,那问题出在网络或前端代理环节。 - tcpdump抓包验证:在Docker容器内执行
tcpdump -i any port 80 -A -s 0,然后发送PUT请求,查看抓包结果里的请求体是否完整。如果抓包能看到1M的完整内容,说明Nginx已接收,问题在后续处理流程。
2. 检查PHP代码读取请求体的方式
这是最容易踩的坑!很多人处理PUT请求时会错误使用$_POST,但$_POST仅对application/x-www-form-urlencoded或multipart/form-data类型的POST请求有效,PUT的JSON体必须通过php://input读取:
- 临时修改接收代码,添加调试输出:
查看PHP的error log:如果// 在PUT请求处理入口处添加 $rawBody = file_get_contents('php://input'); error_log('Received raw body length: ' . strlen($rawBody)); // 输出首尾部分内容,确认截断位置 error_log('Body start: ' . substr($rawBody, 0, 100)); error_log('Body end: ' . substr($rawBody, -100)); $data = json_decode($rawBody, true); if (json_last_error() !== JSON_ERROR_NONE) { error_log('JSON decode failed: ' . json_last_error_msg()); }strlen($rawBody)确实是8209,说明PHP只拿到这么多内容;如果是1M左右,那可能是后续业务代码里有截断逻辑。
3. 验证Nginx与PHP-FPM的请求传递配置
虽然你已经设置了client_max_body_size 100m和client_body_buffer_size 10m,但还有几个细节要确认:
- 确保
fastcgi_pass_request_body开启:默认值为on,但如果被意外覆盖为off,PHP将无法获取请求体。可以在location ~ \.php$块里显式添加fastcgi_pass_request_body on;。 - 检查Nginx临时文件权限:当请求体超过
client_body_buffer_size时,Nginx会将body写入临时文件,默认路径是/var/lib/nginx/body。进入Docker容器,检查目录权限:
确保所有者是ls -ld /var/lib/nginx/bodywww-data,权限至少为700,否则Nginx无法写入临时文件,可能导致请求体截断。 - 确认
fastcgi_request_buffering状态:如果该值设为off,Nginx会直接将请求体传递给PHP-FPM而不缓冲,网络不稳定时可能导致截断。可以在location ~ \.php$块里添加fastcgi_request_buffering on;(默认即为on,做个确认)。
4. 排查PHP-FPM与PHP.ini的相关配置
- 验证
post_max_size和upload_max_filesize:你在www.conf里设置了100M,但要确认PHP.ini里的同名配置未被覆盖。可以在PHP代码中输出phpinfo(),搜索这两个参数的值,确保是100M。 - 调整
max_input_time:该参数限制PHP读取输入的时间,若请求体较大且网络较慢,可能导致读取不完整。可以在www.conf里添加php_admin_value[max_input_time] = 300。 - 查看PHP-FPM慢日志:你设置了
slowlog = /var/log/fpm/slow.log,检查日志里是否有请求处理超时或异常的记录,这可能间接导致请求体截断。
5. 排查Docker网络与中间代理
因为应用A部署在Docker中,还要考虑网络层面的限制:
- Docker网络模式测试:如果使用桥接模式,可以尝试改为host模式(
--network host)重新测试,看是否还会出现截断问题,排除端口转发的潜在限制。 - 检查前端代理:如果应用A前面有Cloudflare、负载均衡或内网代理,检查这些服务是否有PUT请求体大小限制,很多代理默认会对大请求做截断处理。
- 验证MTU设置:虽然默认MTU为1500,但如果Docker网络的MTU过小,可能导致分片异常(不过一般不会截断到8k)。可以执行以下命令检查:
若MTU远小于1500,尝试调整为更大的值。docker network inspect bridge | grep MTU
6. 确认站点配置的路径正确性
你的站点配置里root /var/www/appB/public;,但这是应用A的配置,是否存在笔误?如果路径错误,可能执行的是旧版本代码(比如代码里有读取8k的限制),这个细节也值得确认。
总结
最可能的原因按优先级排序:
- 代码错误使用
$_POST读取PUT请求体,导致无法获取完整内容; - Nginx临时文件目录权限不足,无法缓冲大请求体;
- 前端代理服务截断了PUT请求的body。
建议先从代码读取方式和Nginx日志验证开始排查,这两个是最常见的问题。
内容的提问来源于stack exchange,提问作者shadyyx
相关产品推荐
相关产品推荐

