Laravel 9+ 部署后前端跨域请求403或被拦截,主因是内置HandleCors中间件未正确启用:需删除fruitcake/laravel-cors、发布并配置config/cors.php、将中间件置于$middlewareGroups['api']、确保Nginx/Apache透传Origin头且放行Access-Control-Allow-*响应头。

Laravel 部署后前端请求 403 或直接被浏览器拦截,大概率不是 CORS 中间件没配,而是它根本没生效——因为 Laravel 9+ 默认已移除 fruitcake/laravel-cors,且中间件注册方式变了。
为什么 CorsMiddleware 加了也不起作用
常见现象:在 app/Http/Kernel.php 的 $middleware 或 $middlewareGroups 里加了 \Fruitcake\Cors\HandleCors::class,但 OPTIONS 预检请求仍 403 或无响应。
- Laravel 9+ 已将 CORS 功能内置到
Illuminate\Http\Middleware\HandleCors,旧包fruitcake/laravel-cors不再兼容 - 如果项目还装着
fruitcake/laravel-cors,它会和内置中间件冲突,导致配置被忽略 - 中间件必须放在
$middlewareGroups['api'](或web)里,不能只放$middleware全局栈——否则静态资源、路由异常等也会被强制校验 - Apache/Nginx 反向代理时,若未透传
Origin头,Laravel 根本收不到跨域信息,中间件形同虚设
怎么正确启用 Laravel 内置 CORS
从 Laravel 9 开始,config/cors.php 是唯一配置入口,中间件自动加载,无需手动注册。
- 运行
php artisan vendor:publish --tag=cors生成配置文件(若没生成,手动创建config/cors.php) - 确认
config/cors.php中'paths'匹配你的 API 路由,比如['api/*', 'sanctum/csrf-cookie'] - 生产环境务必把
'allowed_origins'设为具体域名列表,避免用['*'](cookie 认证下不生效) - 若需携带凭证(如
withCredentials: true),必须同时设置'supports_credentials' => true和'allowed_origins'为非通配符
部署到 Nginx/Apache 后仍失败的检查点
即使 Laravel 层配置正确,反向代理或 CDN 也可能吞掉关键响应头。
- Nginx 配置中必须显式透传
Origin和Access-Control-Request-Headers,并在 location 块加:add_header 'Access-Control-Allow-Origin' '$http_origin' always; - Apache 需启用
mod_headers,并在虚拟主机中加:Header set Access-Control-Allow-Origin "%{HTTP_ORIGIN}e" env=HTTP_ORIGIN - Cloudflare 等 CDN 默认过滤自定义响应头,需在「Rules」里添加「Transform Rule」放行
Access-Control-Allow-*头 - 检查浏览器开发者工具 Network 面板:预检请求(OPTIONS)是否返回 200 且含
Access-Control-Allow-Methods;主请求是否返回Access-Control-Allow-Credentials: true(如需要)
为什么本地开发正常、上线就报错
本质是环境差异放大了配置疏漏。
- 本地用
php artisan serve时,PHP 内置服务器不处理 CORS,浏览器实际没走预检——上线后 Nginx 拦截了 OPTIONS,才暴露问题 - 本地前端常跑在
http://localhost:3000,而生产是https://app.example.com,allowed_origins若写死http://*就失效 - 生产环境可能启用了
APP_DEBUG=false,导致 CORS 配置错误(如路径写错)静默失败,建议先临时开 debug 看是否抛出CorsConfigurationError
最易被忽略的是:Nginx 的 location ~ \.php$ 块里,如果用了 try_files $uri =404 但没配 fastcgi_param HTTP_ORIGIN $http_origin,PHP 进程压根收不到 Origin 头——这时候 Laravel 连判断跨域的机会都没有。











