Access-Control-Allow-Origin头未生效,首要排查响应是否被覆盖或中间件执行顺序错误;必须在return $next($request)后操作响应对象,预检请求需单独处理,且Nginx/CDN等服务器层配置可能覆盖PHP设置。

中间件里加 Access-Control-Allow-Origin 头没生效?先看响应是否被覆盖
Laravel 的中间件顺序很重要,Cors 相关头如果在响应已发送后才加,就完全无效。常见现象是浏览器 Network 面板里看不到你写的头,或者只在预检请求(OPTIONS)里出现,实际请求还是被拦。
真正起作用的位置是:必须在 return $next($request) 之后操作响应对象,否则中间件只是“路过”,没机会改响应头。
- 错误写法:
response()->header(...)或直接改$response->headers前没接住返回值 - 正确姿势:拿到
$next($request)返回的$response,再链式调用header()或用withHeaders() - 别在中间件里用
exit或die,会跳过后续中间件和响应发送流程
Laravel 9+ 自带 Cors 中间件怎么配参数?重点看 config/cors.php
不用手写中间件——Laravel 7 起内置了 fruitcake/laravel-cors(9.2+ 已合并进核心),但默认配置很保守,Access-Control-Allow-Origin 默认只允许 * 在非凭证请求下生效,一旦前端带 credentials: true,就必须指定明确域名,不能用通配符。
-
'allowed_origins' => ['https://your-app.com']:多个域名用数组,别漏协议和端口(http://localhost:3000和http://127.0.0.1:3000是两个不同源) -
'supports_credentials' => true必须显式开启,否则浏览器拒绝带 cookie 的跨域请求 -
'allowed_headers' => ['*']在生产环境慎用,建议列明真实需要的头,如['Content-Type', 'X-Requested-With', 'Authorization'] - 改完配置记得清缓存:
php artisan config:clear,否则新配置不加载
手写中间件时,OPTIONS 请求怎么处理?别漏掉预检响应
浏览器发真实请求前,会先发一个 OPTIONS 预检请求。如果你的手写中间件只处理 GET/POST,那预检就 405 或直接 404,跨域直接失败。
- 中间件里要判断
$request->isMethod('OPTIONS'),如果是,直接return response('', 200)->header(...) - 预检响应至少要带:
Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers - 别在预检响应里塞
Set-Cookie或重定向,浏览器不认 - 如果用了路由模型绑定或策略检查,
OPTIONS请求可能卡在中间件链前面就被拒了,得确保它能快速通过
为什么本地开发正常,上线 Nginx 就跨域失效?查服务器层头覆盖
Nginx/Apache 可能自己加了 Access-Control-Allow-Origin,或者用 add_header 指令覆盖了 PHP 输出的头。更隐蔽的是:Nginx 的 add_header 在 304 响应中不生效,但 Laravel 响应不是 304,所以问题常出在重复设置或指令作用域错位。
- 检查 Nginx 配置里有没有
add_header Access-Control-Allow-Origin "*";—— 如果有,删掉,让 Laravel 全权控制 - 确认
add_header不在location /api这种子块里重复定义,否则可能叠加或冲突 - 用
curl -I https://yoursite.com/api/test直接看原始响应头,绕过浏览器缓存和 CORS 策略干扰 - Cloudflare 等 CDN 也可能注入头,临时关闭代理模式验证
跨域不是单点问题,是请求链路里任意一环写错头、删掉头、或顺序错乱都会断掉。最稳的方式:从浏览器开发者工具 Network → 选请求 → 查看 **Response Headers**,逐个比对每个头的来源,而不是猜中间件有没有跑。











