
本文详解 Laravel 9 及更高版本中如何正确启用内置 CORS 支持,涵盖中间件注册、config/cors.php 核心配置、路径匹配、凭证处理及 Nginx 协同调试,助你 5 分钟安全打通 api/list 和 api/profiles 等接口跨域访问。
本文详解 laravel 9 及更高版本中如何正确启用内置 cors 支持,涵盖中间件注册、config/cors.php 核心配置、路径匹配、凭证处理及 nginx 协同调试,助你 5 分钟安全打通 `api/list` 和 `api/profiles` 等接口跨域访问。
Laravel 9 起已将原 fruitcake/laravel-cors 包的核心逻辑(由 Barry vd H. 开发并长期维护)正式集成至框架底层,由 Dries Vints 主导完成迁移。这意味着你无需再执行 composer require fruitcake/laravel-cors,也不再依赖第三方服务提供者——CORS 功能已成为 Laravel HTTP 层的原生能力,由 \Illuminate\Http\Middleware\HandleCors 中间件统一处理。
✅ 第一步:确认并启用内置 CORS 中间件
打开 app/Http/Kernel.php,确保 \Illuminate\Http\Middleware\HandleCors::class 已注册在全局中间件数组 $middleware 的顶部位置(非 $middlewareGroups['api'] 内):
// app/Http/Kernel.php
protected $middleware = [
\App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class, // ← 必须在此处,且靠前!
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
// ... 其他中间件
];⚠️ 关键说明:
- 若仅将其放在
$middlewareGroups['api']中(如常见于旧教程),则Route::get('api/list', ...)等未显式套用middleware('api')的路由将完全不受控; - 对
api/list、api/profiles这类标准 API 路径,推荐全局启用,避免遗漏; - 升级至 Laravel 13.2.0(当前最新稳定版)后,该中间件默认存在,但仍需人工核对是否被误删或顺序错位。
✅ 第二步:发布并配置 config/cors.php
运行命令生成配置文件(Laravel 9+ 虽已内置,但自定义配置仍需此步):
php artisan vendor:publish --tag="cors"
编辑 config/cors.php,针对 api/list 与 api/profiles 接口,推荐以下安全且可扩展的配置:
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
// config/cors.php
return [
'paths' => ['api/*', 'sanctum/csrf-cookie'], // ✅ 覆盖所有 api/ 开头路径(含 list、profiles)
'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], // ❌ 避免 ['*'],防止某些 CDN/Nginx 拒绝未知 method
'allowed_origins' => [
'http://localhost:3000', // 开发环境前端
'https://your-app.com', // 生产环境主站
'https://admin.your-app.com', // 多子域场景
],
'allowed_headers' => ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept'],
'exposed_headers' => ['X-RateLimit-Limit', 'X-RateLimit-Remaining'], // 如需 JS 读取限流头,必须显式声明
'supports_credentials' => true, // ✅ 若前端 fetch 使用 credentials: 'include' 或使用 Sanctum 登录态,必须设为 true
'max_age' => 3600,
];? 注意事项:
-
supports_credentials => true时,allowed_origins*绝对禁止使用 `['']**,否则浏览器会报错A wildcard '*' cannot be used`; - 开发阶段务必精确匹配协议、域名、端口(如
http://localhost:3000≠http://127.0.0.1:3000); -
paths中'api/*'已覆盖api/list与api/profiles,无需单独添加。
✅ 第三步:Nginx 层协同 —— 不可绕过的 OPTIONS 透传
即使 Laravel 配置完美,若 Nginx 拦截了浏览器预检请求(OPTIONS),中间件根本不会执行。在 Nginx 配置中(如 server 块内),必须显式处理 OPTIONS 方法并返回 204:
# Nginx 配置片段
location / {
# 允许跨域请求头(动态反射 Origin)
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, 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-RateLimit-Limit, X-RateLimit-Remaining' always;
# 处理预检请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 86400;
add_header 'Access-Control-Allow-Origin' '$http_origin';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';
add_header 'Access-Control-Allow-Credentials' 'true';
return 204;
}
try_files $uri $uri/ /index.php?$query_string;
}? 验证技巧:
- 在 Chrome DevTools → Network → 找到
OPTIONS请求 → 查看 Response Headers 是否含Access-Control-Allow-Origin; - 若返回 404/405,说明 Nginx 未接管 OPTIONS,Laravel 未收到请求;
- 若返回 200 但无 CORS 头,说明中间件未生效(检查 Kernel.php 注册位置)。
? 总结:三要素缺一不可
| 层级 | 关键动作 | 常见失效原因 |
|---|---|---|
| PHP 层 |
HandleCors 置于 $middleware 顶部 + config/cors.php 正确配置 |
中间件位置错误、paths 未覆盖目标路由、supports_credentials 与 allowed_origins 冲突 |
| Web Server 层 | Nginx 显式响应 OPTIONS 并返回 204 + 透传必要头 | Nginx 默认拒绝 OPTIONS、未配置 add_header 或 if 判断失效 |
| 前端层 | fetch 请求中明确设置 credentials: 'include'(如需 Cookie) |
忘记 credentials 导致后端无法识别登录态,返回 401 |
完成以上配置后,api/list 与 api/profiles 将稳定支持跨域调用,且符合生产环境安全规范。Laravel 13.2.0(基于 PHP 8.3+)进一步优化了中间件生命周期与响应头合并逻辑,确保 CORS 头不被后续中间件覆盖——你只需专注业务,跨域交由框架可靠保障。

















