根本原因是header()调用前存在输出(如bom、空格、echo等),导致php静默丢弃响应头;需确保文件为无bom的utf-8编码,且header()在任何输出之前执行。

PHP 后端跨域被拦截,根本原因不是“没加 header”,而是 header('Access-Control-Allow-Origin') 没生效——它被提前输出、脚本错误或缓存代理拦腰截断了。
header('Access-Control-Allow-Origin') 为什么总不生效
浏览器只看响应头,但 PHP 的 header() 函数要求:必须在任何输出(含空格、BOM、echo、var_dump、甚至 require 的文件里的一行空白)之前调用。一旦有输出,PHP 就会静默丢弃后续所有 header() 调用,且不报错。
- 检查 PHP 文件是否为「无 BOM 的 UTF-8」编码(VS Code 底部状态栏点编码 → “Save with Encoding” → “UTF-8”)
- 确认
header()前没有print、echo、?><?php之间的空行,也没有被error_reporting(E_ALL)触发的 Notice 输出 - 如果用了
require或include,要逐个检查被引入文件的开头——哪怕一个空格也会让主文件的header()失效 - 框架项目(如 Laravel、ThinkPHP)别在控制器里硬写
header(),优先走中间件或响应构造器,否则容易被框架自身输出干扰
带 Cookie 或 Authorization 时必须指定域名
只要前端 fetch 设置了 credentials: 'include',或 jQuery ajax 中设置了 xhrFields: {withCredentials: true},后端就不能用 * 通配 Access-Control-Allow-Origin,否则浏览器直接拒绝响应。
使用tbot机器ID身份文件配合tsh CLI,通过Teleport访问控制SSH登录托管主机或执行远程命令。
- 必须写成具体协议+域名+端口,例如:
header('Access-Control-Allow-Origin: https://admin.example.com'); - 必须同时设置另外两个头:
header('Access-Control-Allow-Credentials: true');和header('Access-Control-Allow-Headers: Content-Type, Authorization'); - 前端请求必须显式带上凭证,否则浏览器不会发送 Cookie,后端也收不到
Authorization头
OPTIONS 预检请求必须手动响应
当请求含自定义 Header(如 Authorization)、非简单方法(如 PUT、DELETE)或非简单 Content-Type(如 application/json)时,浏览器会先发一个 OPTIONS 请求探路。这个请求不会进你写的业务逻辑,PHP 脚本若没处理,就直接 404 或 500,导致跨域失败。
- 在入口脚本最开头加判断:
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { header('Access-Control-Allow-Origin: https://admin.example.com'); header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, Authorization'); exit(0); } -
.htaccess里的Header set对OPTIONS无效,除非用RewriteRule显式重写到一个空 PHP 文件 - 不要依赖 Nginx/Apache 全局配置覆盖预检——它没法动态读取
Origin做白名单校验
允许多个域名需动态校验 Origin
硬写多个 header('Access-Control-Allow-Origin: ...') 会触发「Multiple Access-Control-Allow-Origin headers」错误。正确做法是白名单数组 + 动态匹配。
- 获取原始来源:
$origin = $_SERVER['HTTP_ORIGIN'] ?? ''; - 定义白名单:
$allowed = ['https://admin.example.com', 'https://dev.example.com']; - 只对匹配的 Origin 设置响应头:
if (in_array($origin, $allowed)) { header("Access-Control-Allow-Origin: $origin"); } - 注意:不能用
$_SERVER['HTTP_REFERER']替代HTTP_ORIGIN,前者可伪造,后者由浏览器严格提供
最容易被忽略的是:预检请求(OPTIONS)和主请求共用同一套 Origin 白名单逻辑;而框架自动注入的 CORS 中间件,往往默认放行 *,却忘了关掉子模块重复注册的 CORS 配置——结果网关和下游服务各回一个 Access-Control-Allow-Origin,直接触发浏览器报错。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










