浏览器拦截跨域请求源于同源策略,PHP需正确设置响应头:动态匹配Origin白名单、处理OPTIONS预检、配置Credentials及Headers细节,否则仍会失败。

浏览器拦截跨域请求不是 PHP 的问题,而是前端发起请求时触发了同源策略限制;PHP 后端只需正确设置响应头即可放行,但必须注意请求方法、凭证、头字段等细节,否则仍会失败。
Access-Control-Allow-Origin 必须明确指定或动态匹配
静态写死 * 虽然简单,但一旦前端携带了 credentials(如 Cookie 或 Authorization),浏览器会直接拒绝该响应。此时必须显式写出允许的源(如 https://example.com),或在 PHP 中根据 Origin 请求头动态判断并回写:
if (isset($_SERVER['HTTP_ORIGIN'])) {
$origin = $_SERVER['HTTP_ORIGIN'];
// 白名单校验,避免任意源反射
$allowed_origins = ['https://a.com', 'https://b.net'];
if (in_array($origin, $allowed_origins)) {
header("Access-Control-Allow-Origin: $origin");
header('Access-Control-Allow-Credentials: true');
}
}
- 不要无条件返回
Access-Control-Allow-Origin: *+Access-Control-Allow-Credentials: true,这会被浏览器忽略 -
Origin头可能为空(比如本地 file:// 协议或 curl 测试),需判空避免警告 - 生产环境务必做白名单校验,防止 CORS 滥用导致敏感数据泄露
预检请求(OPTIONS)必须被 PHP 正确响应
当请求含自定义头(如 Authorization)、非简单方法(如 PATCH)、或 Content-Type 为 application/json 时,浏览器会先发一次 OPTIONS 预检。若 PHP 没处理该请求,Nginx/Apache 可能直接返回 405 或 404,导致跨域失败。
在入口文件(如 index.php)开头加:
立即学习“PHP免费学习笔记(深入)”;
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
header('Access-Control-Max-Age: 86400');
exit(0);
}
-
Access-Control-Allow-Headers必须包含前端实际发送的自定义头,漏一个就会预检失败 -
Access-Control-Allow-Methods不用穷举所有方法,只需覆盖当前接口用到的即可 - 某些框架(如 Laravel)会自动处理 OPTIONS,但原生 PHP 或微框架常需手动补全
Credentials 和 Cookie 传递需前后端协同配置
若前端设置了 credentials: 'include',后端除了返回 Access-Control-Allow-Origin(不能是 *)和 Access-Control-Allow-Credentials: true,还需确保 PHP 的 session 或登录态能被识别:
- 确认
session_start()已调用,且未因 header 已发送而报错 - Apache 下检查是否启用了
mod_headers,Nginx 下确认未用add_header覆盖掉 PHP 输出的 CORS 头 - 前端 fetch 要带
credentials: 'include',axios 则需设withCredentials: true - PHP 中
setcookie()若未指定$domain和$secure,跨域下 Cookie 可能不被携带
最易被忽略的是预检响应中缺失 Access-Control-Allow-Headers,或后端没真正响应 OPTIONS 请求——这时候浏览器控制台只显示 “CORS error”,但 Network 面板里能看到 OPTIONS 返回了 404 或 500,而不是 200 带正确头。排查时一定先看预检那条请求的响应头是否完整。











