Laravel 10.x 解决前后端分离跨域问题 CORS中间件配置全攻略(含API与Cookie互通方案)

发布于 更新于
3

在前后端分离架构中,Laravel 作为后端 API 服务时常面临浏览器同源策略限制。本文详细讲解如何在 Laravel 10.x 版本中通过自定义中间件及官方 fruitcake/laravel-cors 包两种方式,系统化配置 CORS(跨域资源共享)。内容涵盖预检请求(Preflight Request)处理、携带 Cookie 认证、多域名白名单设置及常见报错排查,提供可直接复用的代码配置,助力快速解决跨域拦截问题。

引言

当前端应用(如 Vue.js、React 或纯 JavaScript)部署在 http://localhost:8080,而后端 Laravel API 部署在 http://api.example.com 时,浏览器出于安全考虑会默认拦截跨域请求。典型报错包括 No 'Access-Control-Allow-Origin' header is presentResponse to preflight request doesn't pass access control check。正确配置 CORS 中间件是打通前后端数据交互的关键步骤。

一、 理解 CORS 核心响应头

在配置中间件前,需明确关键响应头含义:

  • Access-Control-Allow-Origin:指定允许访问资源的源(域名)。

  • Access-Control-Allow-Methods:指定允许的 HTTP 方法(GET, POST, PUT, DELETE 等)。

  • Access-Control-Allow-Headers:指定允许的请求头(Content-Type, Authorization, X-Requested-With)。

  • Access-Control-Allow-Credentials:布尔值,指示是否允许发送 Cookie。

  • Access-Control-Max-Age:预检请求的结果缓存时间(秒)。

二、 方案一:自定义 CORS 中间件(推荐用于学习原理)

  1. 创建中间件
    执行 Artisan 命令:

    php artisan make:middleware CorsMiddleware
  2. 编写中间件逻辑

    编辑 app/Http/Middleware/CorsMiddleware.php

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    
    class CorsMiddleware
    {
        public function handle(Request $request, Closure $next)
        {
            // 处理预检请求 (OPTIONS)
            if ($request->isMethod('OPTIONS')) {
                $response = response('', 200);
            } else {
                $response = $next($request);
            }
    
            // 允许的前端域名,生产环境严禁使用 *
            $allowedOrigins = [
                'http://localhost:8080',
                'https://admin.example.com'
            ];
    
            $origin = $request->header('Origin');
    
            if (in_array($origin, $allowedOrigins)) {
                $response->header('Access-Control-Allow-Origin', $origin);
                $response->header('Access-Control-Allow-Credentials', 'true');
            }
    
            $response->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
            $response->header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, X-CSRF-TOKEN');
    
            return $response;
        }
    }
  3. 注册中间件

    app/Http/Kernel.php$middleware 数组(全局中间件)中添加:

    protected $middleware = [
        // ... 其他中间件
        \App\Http\Middleware\CorsMiddleware::class,
    ];

三、 方案二:使用 fruitcake/laravel-cors 扩展包(推荐用于生产环境)

  1. 安装依赖

    composer require fruitcake/laravel-cors
  2. 发布配置文件

    php artisan vendor:publish --tag="cors"
  3. 配置 config/cors.php

    根据需求修改配置,以下为支持 Cookie 互通的配置示例:

    <?php
    
    return [
        'paths' => ['api/*', 'sanctum/csrf-cookie'],
        'allowed_methods' => ['*'],
        'allowed_origins' => [
            'http://localhost:8080',
            'https://admin.example.com'
        ],
        'allowed_origins_patterns' => [],
        'allowed_headers' => ['*'],
        'exposed_headers' => [],
        'max_age' => 86400,
        'supports_credentials' => true, // 关键:允许发送 Cookie
    ];
  4. 全局应用

    app/Http/Kernel.php 中确保 HandleCors 中间件在全局生效:

    protected $middleware = [
        // ...
        \Fruitcake\Cors\HandleCors::class,
    ];

四、 前端配合:Axios 携带 Cookie 配置

若后端开启了 supports_credentials,前端必须设置 withCredentials

import axios from 'axios';

const service = axios.create({
  baseURL: 'http://api.example.com',
  withCredentials: true // 允许携带 Cookie
});

五、 常见问题排查

  • 报错:The value of the 'Access-Control-Allow-Origin' header ...

    原因:当 supports_credentialstrue 时,Access-Control-Allow-Origin 不能为 *。必须指定具体域名。

  • Cookie 无法保存

    检查前端 withCredentials 是否开启,以及后端域名配置是否包含前端当前访问的 Origin。

  • OPTIONS 请求 404

    确保路由定义了 OPTIONS 方法,或使用中间件全局捕获 OPTIONS 请求。

结尾

Laravel 跨域配置的核心在于正确处理 OPTIONS 预检请求及精准控制响应头。对于新项目,建议直接使用 fruitcake/laravel-cors 扩展包,配合清晰的域名白名单策略,既能保证安全性,又能提高开发效率。在生产环境部署时,务必将允许的域名从 localhost 切换为正式域名,避免因配置不当导致的安全漏洞。

常见问题(FAQ)

为什么配置后依然提示跨域错误?
检查浏览器控制台报错信息。若为证书问题(HTTPS 与 HTTP 混合),需统一协议。同时检查中间件注册位置是否正确,全局中间件应放在 Kernel.php 的 $middleware 数组中,而非 $routeMiddleware。
生产环境允许所有域名()有什么风险?
允许所有域名会暴露 API 接口给任何网站,可能导致 CSRF 攻击或数据泄露。生产环境务必指定具体的可信域名列表。
Laravel Sanctum 或 Passport 认证下如何配置跨域?
原理相同。需确保 cors.php 中 paths 包含 Sanctum 的 CSRF Cookie 路由(如 sanctum/csrf-cookie),且 supports_credentials 设置为 true。
预检请求(OPTIONS)的作用是什么?
预检请求是浏览器发送的一种 HTTP OPTIONS 请求,用于询问服务器是否允许实际的请求方法和头部。服务器必须正确响应 OPTIONS 请求,后续的 POST、PUT 等请求才能正常发送。
如何区分 API 路由和 Web 路由的跨域策略?
可在 routes/api.php 中单独使用路由中间件,或者在 cors.php 配置文件的 paths 项中指定仅对 api/* 生效,避免对 Web 页面造成不必要的性能开销。
0 讨论
热门最新
总结
暂无总结
0 / 600
嗨,下午好!
所有的成功,都源自一个勇敢的开始
¥10.00
10元抵扣券
已过期