ThinkPHP中$request->header('Content-Length')返回null是因为PHP将该头映射为$_SERVER['CONTENT_LENGTH']而非HTTP_CONTENT_LENGTH,需用$request->server('CONTENT_LENGTH')获取;getRawContent()在multipart请求中失效,CONTENT_LENGTH是唯一可信的请求体总长度来源。

ThinkPHP中$request->header('Content-Length')返回null?
直接调用 $request->header('Content-Length') 在多数情况下会返回 null,不是框架 bug,而是 PHP 的 $_SERVER 变量对这个头的映射规则特殊——它不走 HTTP_* 前缀,而是直接存为 CONTENT_LENGTH(全大写、无下划线)。
ThinkPHP 的 header() 方法底层依赖 $_SERVER,但默认只按 HTTP_XXX 规则查找,漏掉了这个特例。
- 正确获取方式是手动查
$_SERVER['CONTENT_LENGTH'],或用兼容写法:$request->server('CONTENT_LENGTH') -
$request->server()是唯一能稳定命中CONTENT_LENGTH的入口,它绕过 header 映射逻辑,直读$_SERVER - 注意:该值是字符串,需用
(int)转换;若请求体为空(如 GET),可能为0或空字符串 - 不要用
$request->header('content-length')(小写)、$request->header('Content-length')(大小写混用),都不可靠
为什么不能只靠 getRawContent() 判断请求体大小
$request->getRawContent() 对 JSON、纯文本等非 multipart 请求有效,但遇到文件上传(multipart/form-data)时,PHP 已提前将 body 写入临时文件并清空 php://input 流,此时 getRawContent() 返回空字符串,不代表没发数据。
这时候 $request->server('CONTENT_LENGTH') 就成了唯一可信的总长度来源——它由 Web 服务器(Nginx/Apache)在接收完整请求后填入,包含所有字段、参数和文件字节。
- GET 请求:CONTENT_LENGTH 恒为 0(无 body),忽略即可
- POST 表单(不含文件):CONTENT_LENGTH ≈
strlen($request->getRawContent()),二者可交叉验证 - 含文件上传的 POST/PUT:
getRawContent()失效,必须依赖CONTENT_LENGTH - 某些代理或 CDN 可能剥离或改写该头,生产环境建议加日志比对实际上传文件大小
中间件里统计原始请求体积的推荐写法
要在中间件中准确统计「客户端到底发了多少字节」,必须同时覆盖 QUERY_STRING(GET 参数)和请求体(含 CONTENT_LENGTH fallback),且顺序不能错——因为 getRawContent() 只能读一次。
- 先判断请求方法:
strtoupper($request->method()) - GET:用
strlen($request->server('QUERY_STRING') ?: '') - 非-GET:优先
$raw = $request->getRawContent();若为空,则退到(int)$request->server('CONTENT_LENGTH', 0) - 注意:不要在控制器里再调
getRawContent(),中间件已消耗流,后续会返回空 - 如果用了 Swoole 或 RoadRunner 等常驻内存模型,CONTENT_LENGTH 仍可靠,但需确认 Swoole 配置未禁用该 server 变量
真正容易被忽略的是 multipart 场景下 getRawContent() 的静默失效——它不报错,只返回空,开发者若没 fallback 到 CONTENT_LENGTH,就会误判为“空请求”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











