PHP-FPM不处理跨域头,必须由Nginx或PHP层显式添加;常见原因包括PHP输出前有BOM/空格、fastcgi_hide_header屏蔽头、add_header未配always覆盖失效,应通过curl -I分层排查并统一在PHP设头或Nginx用add_header ... always;兜底。

PHP-FPM 本身不直接处理 HTTP 请求头(包括跨域相关头),它只负责执行 PHP 脚本。跨域响应头(如 Access-Control-Allow-Origin)必须由 Nginx 或 PHP 应用层显式添加。当 Nginx 作为反向代理将请求转发给 PHP-FPM(通常通过 fastcgi_pass)时,若出现“跨域头丢失”,根本原因通常是 Nginx 配置未透传或覆盖了 PHP 输出的 CORS 头,或 PHP 脚本未正确输出这些头。
确认 PHP 是否真正输出了跨域头
先排除 PHP 层问题:在 PHP 脚本开头(或框架中间件中)明确设置响应头,且确保未被后续逻辑覆盖:
- 使用
header('Access-Control-Allow-Origin: *');或指定域名(如https://example.com) - 若需携带凭证(cookies),必须写具体域名,不能用
*,并加header('Access-Control-Allow-Credentials: true'); - 检查是否调用了
header()前已有输出(空白符、BOM、echo),否则会报 “headers already sent” 错误,导致头完全失效 - 可通过
curl -I http://your-site/api.php直接访问 PHP 文件,验证响应头是否存在
Nginx FastCGI 配置需保留 PHP 输出的头
Nginx 默认不会过滤 PHP-FPM 返回的响应头,但以下配置可能意外清除或覆盖它们:
-
避免滥用
fastcgi_hide_header:该指令会屏蔽 PHP 输出的指定头。检查配置中是否写了类似fastcgi_hide_header Access-Control-Allow-Origin;—— 若有,立即删除 -
慎用
add_header在 location 块中覆盖:若在location ~ \.php$中用了add_header,它只对 Nginx 生成的响应生效;而 PHP-FPM 返回的是“已生成响应”,add_header默认不生效(除非配always)。更稳妥做法是让 PHP 自己输出,或统一在 server/location 级用add_header ... always; - 确保
fastcgi_pass后紧跟标准 FastCGI 参数集(如fastcgi_params),其中不含干扰响应头的指令
推荐的 Nginx + PHP-FPM 跨域安全配置
兼顾灵活性与安全性,建议在 PHP 中控制基础 CORS,Nginx 仅兜底或补充关键头:
立即学习“PHP免费学习笔记(深入)”;
- PHP 中统一设置:
header('Access-Control-Allow-Origin: ' . ($_SERVER['HTTP_ORIGIN'] ?? ''));
配合验证HTTP_ORIGIN白名单,防止任意源伪造 - Nginx 中(server 或 location 块)添加兜底头(仅当 PHP 未输出时生效):
add_header 'Access-Control-Allow-Origin' '$http_origin' always;add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; - 对预检请求(OPTIONS)单独返回 204:
if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin "$http_origin"; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE"; add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"; add_header Access-Control-Max-Age 1728000; add_header Content-Type 'text/plain; charset=utf-8'; add_header Content-Length 0; return 204; }
调试技巧:快速定位头丢失环节
分层排查比盲目改配置更高效:
- 用
curl -v http://localhost/test.php(直连 PHP-FPM 所在端口,绕过 Nginx)看原始响应头 → 判断是否 PHP 问题 - 用
curl -v http://your-domain/test.php(走完整 Nginx 链路)对比差异 → 确认是否 Nginx 干预 - 临时在 Nginx 的
log_format中加入$sent_http_access_control_allow_origin,记录实际发出的 CORS 头值 - 检查 Nginx 错误日志(
error_log)是否有upstream sent too big header类警告——大响应头可能被截断,可调大fastcgi_buffer_size和fastcgi_buffers



















