推荐nginx全权拦截并响应跨域预检options请求,php专注业务逻辑;nginx配置if判断options并返回204及带always的cors头,php仅对非预检请求动态设置origin等头。

PHP 跨域预检 OPTIONS 请求,推荐由 Nginx 全权拦截并响应,PHP 层专注业务逻辑——这是最稳定、低延迟、易维护的联合处理方式。Nginx 做好预检兜底,PHP 就不用写重复逻辑、也不怕框架路由未覆盖导致 404;同时保留 PHP 对正式请求(如 POST/PUT)添加动态 CORS 头的能力,兼顾安全与灵活性。
一、Nginx 拦截 OPTIONS 并返回 204
在 server 或 location 块中单独配置一个 OPTIONS 处理分支,必须前置、独立、不混用 proxy_pass:
- 用 if ($request_method = 'OPTIONS') 判断,仅放在 server 或 location 内(不可嵌套在 if 中)
- 所有 add_header 必须带 always 参数,否则 204 响应不会携带 CORS 头
- 返回 204 No Content,不带响应体,语义准确且兼容性好
- 示例关键配置:
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Requested-With' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Max-Age' '86400' always;
return 204;
二、PHP 只对非预检请求设置响应头
PHP 不再需要响应 OPTIONS,只需在正常接口入口(如 index.php 或控制器开头)为实际业务响应注入 CORS 头,且必须满足:
- header() 调用在 任何输出之前(包括空格、BOM、echo)
- 若前端带 credentials(如 cookie),Access-Control-Allow-Origin 不能为 *,需动态匹配 Origin
- 建议配合 $_SERVER['HTTP_ORIGIN'] 做白名单校验,例如:
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
$allowed = ['https://admin.example.com', 'https://app.example.io'];
if (in_array($origin, $allowed)) {
header("Access-Control-Allow-Origin: $origin");
header('Access-Control-Allow-Credentials: true');
}
三、避免常见组合陷阱
联合方案失效,往往出在 Nginx 和 PHP 的交界处:
- 禁用 if + proxy_pass 同块写法:会导致 proxy_set_header 失效、502、Host 丢失
- 不要让 PHP 处理 OPTIONS:即使 Nginx 转发了,PHP 也容易因路由未命中或输出污染导致失败
- Origin 白名单必须两端一致:Nginx 预检响应和 PHP 正式响应中的 Allow-Origin 值应来源相同,否则浏览器会拒绝
- 检查 Nginx 是否拦截了 OPTIONS:用 curl -I -X OPTIONS http://your-api.com/api/test 确认响应含全部 CORS 头且状态为 204
四、进阶:动态 Origin 与缓存优化
面向多前端或测试环境时,可提升安全性与复用性:
- 用 map 指令定义可信 Origin 白名单,避免硬编码或正则性能损耗
- 为 OPTIONS 响应加 Cache-Control "public, max-age=86400",减少重复预检
- 设置 Access-Control-Max-Age 86400,让浏览器缓存预检结果一天
- 确保该 location 块中 proxy_cache_bypass off,防止缓存策略跳过预检处理
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











