最可靠方式是通过$_SERVER变量手动提取请求头,因getallheaders()仅限Apache SAPI且在FPM/CLI等环境不可用;需按规则转换头名(如X-Request-ID→HTTP_X_REQUEST_ID),注意Content-Type/Length无HTTP_前缀,并确保Nginx配置underscores_in_headers on及正确fastcgi_param透传。

PHP 获取请求头信息,最可靠的方式是使用 getallheaders() 函数(仅限 Apache SAPI),但该函数在 CLI、FPM、Nginx 等环境下不可用;生产环境应优先通过 $_SERVER 变量手动提取,避免依赖 SAPI 特性。
为什么 getallheaders() 经常返回空或报错
这个函数不是 PHP 核心函数,而是 Apache 模块(mod_php)提供的扩展能力。当 PHP 运行在 FPM(如 Nginx + PHP-FPM)、CLI 或某些容器环境中时,getallheaders() 直接不存在,调用会触发 Fatal error: Uncaught Error: Call to undefined function getallheaders()。
- 仅在 Apache + mod_php 下可用;Nginx + PHP-FPM 必须绕过
- 即使存在,某些反向代理(如 Cloudflare)可能过滤或重写原始头,
getallheaders()返回的是“到达 PHP 进程时的头”,不一定是客户端发出的原始头 - 部分服务器配置禁用该函数(出现在
disable_functions中)
从 $_SERVER 安全提取请求头的通用写法
所有 SAPI 都会将 HTTP 头映射为 $_SERVER 键,规则是:头名转大写、中划线变下划线、加前缀 HTTP_。例如 X-Request-ID → $_SERVER['HTTP_X_REQUEST_ID'],Content-Type → $_SERVER['HTTP_CONTENT_TYPE']。
- 注意
Content-Type和Content-Length是例外:它们映射为$_SERVER['CONTENT_TYPE']和$_SERVER['CONTENT_LENGTH'](无HTTP_前缀) - 建议封装成函数并做空值判断,避免 Notice:
function getHeader(string $name): ?string { $key = 'HTTP_' . str_replace('-', '_', strtoupper($name)); if ($name === 'Content-Type') { $key = 'CONTENT_TYPE'; } elseif ($name === 'Content-Length') { $key = 'CONTENT_LENGTH'; } return $_SERVER[$key] ?? null; } // 使用 $token = getHeader('Authorization'); $id = getHeader('X-Request-ID'); - 大小写不敏感,但
$_SERVER键本身区分大小写,务必统一转大写处理
Nginx 下必须设置 underscores_in_headers on
默认 Nginx 会丢弃含下划线的请求头(如 X_Api_Key),即使你写了 fastcgi_param HTTP_X_API_KEY $http_x_api_key,Nginx 也不转发。不配这个指令,$_SERVER['HTTP_X_API_KEY'] 就永远是空。
- 在
http或server块中添加:underscores_in_headers on;
- 同时确保
fastcgi_param正确透传,例如:fastcgi_param HTTP_AUTHORIZATION $http_authorization;
(否则Authorization头在 FPM 中不可见) - 重启 Nginx 后生效,仅影响新连接
真正麻烦的不是“怎么取”,而是“哪个头能取到”——代理链越长,头被吞得越多;Authorization 在 Nginx 默认不透传,X-Forwarded-For 可能被伪造,Host 被重写成后端地址……别只盯着 PHP 怎么读,先确认头是不是真到了 PHP 进程里。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











