php 7.4 处理 gzip 编码 post 请求需手动解压:先用 file_get_contents('php://input') 读取原始数据,再以 substr($raw, 0, 2) === "\x1f\x8b" 检测魔数判断是否 gzip,成功则 gzdecode($raw) 解压并注入请求上下文,否则返回 400。

PHP 7.4 处理 Gzip 编码的 POST 请求,核心在于:服务端(PHP)收到的是压缩后的原始请求体,而 Laravel、ThinkPHP 或原生 $_POST/file_get_contents('php://input') 都不会自动解压它。必须手动检测并解压,否则 $request->all() 为空、JSON 解析失败、php://input 是乱码。
判断是否为 Gzip 请求体
检查原始输入流开头是否为 gzip 魔数 \x1f\x8b —— 这是最可靠的方式,不依赖请求头是否写了 Content-Encoding: gzip(有些客户端漏写,但实际发了压缩数据):
- 用
file_get_contents('php://input')读取原始数据 - 用
substr($raw, 0, 2) === "\x1f\x8b"判断 - 注意:不能用
$_SERVER['HTTP_CONTENT_ENCODING']做唯一依据,它可能缺失或被代理篡改
手动解压并替换请求流(推荐做法)
在框架路由解析前完成解压,确保后续所有逻辑(验证、参数提取、中间件)都基于明文数据:
- 调用
gzdecode($raw)解压(PHP 7.4 默认支持,无需额外扩展) - 解压失败时返回
400 Bad Request,避免静默错误 - 将解压后的内容重新注入请求上下文:
→ 原生 PHP:覆盖php://input不可行,需在业务逻辑开头重读并处理
→ Laravel:用中间件调用$request->duplicate([], [], Stream::create($decoded))
→ ThinkPHP:可重写input()行为或在控制器首行手动解压
发送 Gzip 请求体给第三方接口(反向场景)
如果你是客户端,要向其他服务 POST Gzip 压缩的数据(极少见,仅当对方文档明确要求):
- 先构造原始 payload(如 JSON 数组),再用
gzencode($json, 9)压缩 - 设置请求头:
Content-Encoding: gzip和Content-Length: ' . strlen($compressed) - 使用 cURL:
curl_setopt($ch, CURLOPT_POSTFIELDS, $compressed) - 切勿用
gzcompress()或gzdeflate(),它们不生成标准 gzip 格式,服务端大概率拒绝
不要踩的坑
这些常见做法在 PHP 7.4 下无效或危险:
-
file_get_contents('compress.zlib://...')只适用于 GET 场景,对 POST 请求体无用 -
zlib.output_compression=On是控制响应压缩的,和接收请求体无关 - 依赖
Accept-Encoding: gzip请求头来决定是否解压 —— 它只影响你“能接收什么响应”,和服务端“发没发 gzip 请求体”完全无关 - 用
gzinflate(substr($data,2,-4))处理 gzip 数据 —— 这是针对 deflate 格式的老方法,对标准 gzip 会出错
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











