laravel 11 生产环境 cors 配置必须禁用通配符,显式声明可信 https 域名;仅对 api 路由启用 handlecors 中间件;开启 supports_credentials 并匹配前端 credentials: 'include';避免 php 与 nginx 双重设置 cors 头。

Laravel 11 默认已集成 fruitcake/laravel-cors 的核心逻辑(自 Laravel 9 起逐步内建),但*生产环境必须禁用通配符 `,并显式声明可信域名**,否则既不安全,也不符合浏览器对Access-Control-Allow-Credentials` 的强制要求。
以下为适用于 Laravel 11 生产环境的 CORS 配置要点,兼顾安全性、兼容性与可维护性:
明确限定 allowed_origins,禁止使用 *
浏览器在响应头中包含 Access-Control-Allow-Credentials: true(如需携带 Cookie 或 Authorization)时,Access-Control-Allow-Origin *绝不允许是 ``**。生产环境通常需要认证,因此必须列出具体域名:
// config/cors.php
'allowed_origins' => [
'https://app.yourcompany.com',
'https://admin.yourcompany.com',
'https://staging.yourcompany.com',
],
⚠️ 注意:
- 不要写
http://开头的域名(除非明确支持非 HTTPS); - 子域名需逐个列出,或用正则(需自定义中间件支持,原生包不支持通配符域名如
https://*.yourcompany.com); - 开发环境可临时保留
['http://localhost:3000'],但上线前必须替换。
仅对 API 路由启用 CORS 中间件
避免影响 Web 页面(如 Blade 渲染页、登录页等),推荐将 CORS 中间件注册到 api 路由组而非全局:
// app/Http/Kernel.php
protected $middlewareGroups = [
'api' => [
\Fruitcake\Cors\HandleCors::class, // ✅ 放在这里
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
这样 /api/* 下的所有路由受控,而 /login、/ 等 Web 路由不受影响,也更符合前后端分离架构。
配置 supports_credentials 和对应 headers
若前端需发送带 Cookie 的请求(例如 Sanctum 的会话认证),需同时开启:
'supports_credentials' => true, 'allowed_headers' => ['Content-Type', 'X-Requested-With', 'Authorization'], 'exposed_headers' => ['X-CSRF-TOKEN'], // 如需暴露 CSRF Token 给前端
配套地,前端 Axios 或 Fetch 必须设置 credentials: 'include',否则浏览器不会发送 Cookie。
避免中间件重复添加响应头
Laravel 11 的 HandleCors 中间件默认会跳过已含 CORS 头的响应。但若你还在 Nginx/Apache 层手动加了 add_header Access-Control-Allow-Origin ...,可能导致响应头重复,触发浏览器拒绝(尤其是 Vary 头冲突)。建议:
- ✅ 选择 PHP 层(中间件)或服务器层(Nginx)只用一种方式;
- ❌ 不要两者混用,除非你精确控制
always参数和 header 合并逻辑。
补充:Nginx 生产部署推荐(轻量可靠)
若希望卸载 PHP 层压力,且 API 全部走 Nginx 反向代理,可直接在 server 块中配置(比 PHP 更快、更稳定):
location /api/ {
proxy_pass http://php-upstream;
proxy_set_header Host $host;
# CORS headers
add_header 'Access-Control-Allow-Origin' 'https://app.yourcompany.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Expose-Headers' 'X-CSRF-TOKEN' always;
# 预检请求直接返回 204
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}
⚠️ 注意:
add_header ... always是关键,否则 Nginx 在 301/302 重定向时可能不传递 CORS 头。
不复杂但容易忽略。











