laravel 7 默认不内置 cors 中间件,需手动配置处理 options 预检请求:返回 200 状态码并设置 access-control-allow-origin、methods、headers 等响应头,且 supports_credentials 为 true 时 allowed_origins 不可为 *。

Laravel 7 默认不内置 CORS 中间件,预检请求(OPTIONS)不会被自动处理,必须手动配置才能让浏览器通过校验。核心在于:让 OPTIONS 请求返回 200 状态码,并带上正确的 CORS 响应头,且不执行后续业务逻辑。
预检请求必须满足的条件
浏览器发起非简单请求(如带 Authorization 头、Content-Type: application/json、或使用 PUT/DELETE)前,会先发一个 OPTIONS 请求。服务器必须响应:
- 状态码
200 OK - 包含
Access-Control-Allow-Origin(不能是*+credentials共存) - 包含
Access-Control-Allow-Methods - 包含
Access-Control-Allow-Headers - 若需携带 Cookie,还需
Access-Control-Allow-Credentials: true
方法一:用 fruitcake/laravel-cors 包(推荐)
Laravel 7 支持该包,它是当时最稳定、适配性最好的 CORS 解决方案。
-
安装包
composer require fruitcake/laravel-cors
-
发布配置
php artisan vendor:publish --provider="Fruitcake\Cors\CorsServiceProvider"
-
编辑
config/cors.php,关键项示例:'paths' => ['api/*'], 'allowed_origins' => ['http://localhost:3000', 'https://your-frontend.com'], 'allowed_methods' => ['*'], 'allowed_headers' => ['Content-Type', 'X-Requested-With', 'Authorization'], 'supports_credentials' => true, // 如需 Cookie,此项为 true,allowed_origins 就不能写 ['*']
-
注册中间件
打开app/Http/Kernel.php,将中间件加入$middlewareGroups['api'](不要加到全局$middleware,避免影响登录页等非 API 请求):'api' => [ \Fruitcake\Cors\HandleCors::class, // ... 其他中间件 ],
✅ 这样配置后,所有匹配
api/*的路由(包括OPTIONS)都会由中间件拦截并正确响应预检。
方法二:自定义中间件(轻量、无依赖)
适合不想引入第三方包,或需动态控制来源的场景。
-
创建中间件
php artisan make:middleware HandleCors
-
编辑
app/Http/Middleware/HandleCors.php的handle()方法:public function handle($request, Closure $next) { // 如果是 OPTIONS 请求,直接返回空响应并设置头 if ($request->isMethod('OPTIONS')) { return response('', 200) ->header('Access-Control-Allow-Origin', 'http://localhost:3000') ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') ->header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With') ->header('Access-Control-Allow-Credentials', 'true'); } // 正常请求:添加响应头 $response = $next($request); $response->headers->set('Access-Control-Allow-Origin', 'http://localhost:3000'); $response->headers->set('Access-Control-Allow-Credentials', 'true'); return $response; } -
注册到
Kernel.php的api组(同上)'api' => [ \App\Http\Middleware\HandleCors::class, // ... ],
⚠️ 注意:Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials 必须严格匹配——若后者为 true,前者绝不能是 *。
方法三:在路由中单独处理 OPTIONS(应急用)
适用于只对个别接口开放跨域,且不想改中间件。
在 routes/api.php 中显式定义 OPTIONS 路由:
// 预检专用路由(必须放在实际路由之前)
Route::options('/login', function () {
return response('', 200)
->header('Access-Control-Allow-Origin', 'http://localhost:3000')
->header('Access-Control-Allow-Methods', 'POST')
->header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
->header('Access-Control-Allow-Credentials', 'true');
});
Route::post('/login', [AuthController::class, 'login']);
⚠️ 缺点:每个需要跨域的接口都得配一条,维护成本高,不推荐长期使用。
常见失败原因排查
-
OPTIONS 请求根本没进 Laravel→ 检查 Nginx/Apache 是否放行OPTIONS方法(常见于反向代理未透传) -
config/cors.php 修改后没生效→ 执行php artisan config:clear -
supports_credentials => true但allowed_origins写了['*']→ 浏览器直接拒绝,报错明确提示 - 前端
fetch或axios用了withCredentials: true,而后端没设Access-Control-Allow-Credentials→ 预检失败
不复杂但容易忽略。











