返回

Laravel 9 CORS详解:跨域资源共享终极指南

vue.js

Laravel 9 中跨域资源共享(CORS)问题详解

在前后端分离的架构中,跨域资源共享(CORS)问题非常常见。当浏览器从一个源(域名、协议或端口)向另一个源发起请求时,会受到浏览器的同源策略限制。例如,Vue.js前端应用(运行于http://127.0.0.1:8080)尝试向Laravel 9 API后端服务(运行于http://localhost:8000)发送请求,此时浏览器就可能会抛出CORS错误。 本文将探讨此问题的根本原因并给出可行的解决方案。

问题

浏览器控制台会显示类似下面的错误:

Access to XMLHttpRequest at 'http://localhost:8000/api' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

这个错误清楚地表明,服务器端的响应头中缺少 Access-Control-Allow-Origin 字段,浏览器据此判断此跨域请求是被禁止的。

原因分析

出现这个问题的根本原因是,默认情况下,服务器响应不会携带CORS相关的头部信息。即使Laravel应用中有默认的config/cors.php 配置,但仅仅依靠此配置文件是不够的。配置仅决定允许哪些源、方法和头部,实际生效仍需要中间件配合。默认的配置没有添加cors中间件,所以服务器发送的响应不会带有 Access-Control-Allow-Origin 等头信息。

解决方案

解决 CORS 问题通常涉及修改服务端响应的头部信息,让浏览器信任这个跨域请求。以下提供多种解决策略。

1. 添加全局 CORS 中间件

Laravel 提供 fruitcake/laravel-cors 包来实现 CORS 配置,并可以将其添加到全局中间件,保证每个API响应都有 CORS 相关头。

步骤:

  1. 安装 fruitcake/laravel-cors 包:

    composer require fruitcake/laravel-cors
    
  2. 打开 app/Http/Kernel.php, 将 \Fruitcake\Cors\HandleCors::class 添加到 $middlewarePriority 数组。

    protected $middlewarePriority = [
        ...
        \Fruitcake\Cors\HandleCors::class, // 添加这行
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \Illuminate\Auth\Middleware\Authenticate::class,
        \Illuminate\Routing\Middleware\ThrottleRequests::class,
        \Illuminate\Http\Middleware\HandlePreflight::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    ];

此后,所有的API响应都会附加CORS相关的头部信息,允许你的前端访问API资源。这种方式简单高效,尤其在需要处理多路由CORS请求的时候。

2. 配置 CORS 文件 cors.php

如果使用了 fruitcake/laravel-cors 包, 则配置文件在 config/cors.php. 你可以在这里指定哪些域允许访问你的后端 API。

return [
    'paths' => ['api/*', 'sanctum/csrf-cookie'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['http://127.0.0.1:8080'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => false,
];
  • paths: 指定哪些路由应用 CORS 规则,可以使用通配符,如 'api/*',表示 api/ 目录下的所有路由。'sanctum/csrf-cookie' 是 Laravel Sanctum 认证时的路由,建议保留。
  • allowed_methods: 允许的 HTTP 请求方法,'*' 表示允许所有。可以配置 'GET', 'POST', 'PUT', 'DELETE' 等。
  • allowed_origins: 允许访问 API 的源。指定特定的域名或者使用'*',允许所有。出于安全考虑,通常不建议使用 *,应该明确指定可以跨域访问你的 API 的域名列表。
  • allowed_origins_patterns: 使用正则表达式匹配来源。这个设置允许使用更加复杂的域名规则。
  • allowed_headers: 允许客户端携带的头部信息, *表示允许所有。
  • exposed_headers: 允许客户端访问的响应头部信息。
  • max_age: 预检请求的缓存时间。
  • supports_credentials: 是否允许客户端携带 credentials,通常用于允许 Cookie 跨域。

修改此配置文件之后, 建议使用 php artisan config:cache 清理配置缓存。

3. 修改 Nginx 或 Apache 配置(服务器层面)

对于部署在 Nginx 或 Apache 等 web 服务器上的 Laravel 项目,也可以在服务器配置层面直接添加 CORS 相关的头部。这样做能够更快地解决问题,因为它不依赖于PHP应用程序的处理。

示例(Nginx):
在你的 server 配置中,可以加入以下配置:

server {
 ...

 location / {
  ...
  add_header 'Access-Control-Allow-Origin' 'http://127.0.0.1:8080';
  add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
  add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type';
 }

   # 对于 OPTIONS 方法请求的特别处理
   if ($request_method = 'OPTIONS') {
       add_header 'Access-Control-Allow-Origin' 'http://127.0.0.1:8080';
       add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
       add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type';
       add_header 'Access-Control-Allow-Credentials' 'true';
       add_header 'Content-Type' 'application/json; charset=UTF-8';
       add_header 'Content-Length' 0;
       return 204;
     }
}

注意: 需要将 'http://127.0.0.1:8080' 修改为你实际的前端访问域名。修改后重启 Nginx 服务器使其生效。类似的操作,也适用与 Apache。

总结与建议

  • 最常用的方法是使用 fruitcake/laravel-cors 中间件配合配置文件,能提供更灵活的管理方式。
  • 仅使用配置文件的cors设置并不生效,必须同时启用相应的中间件。
  • 尽量在服务器端解决 CORS 问题,能减少代码依赖和提高效率。
  • 明确允许的域名,避免在生产环境使用 * 作为 allowed_origins 的值。

通过实施上述方案中的一种或几种,即可有效解决 Laravel 9 应用中遇到的 CORS 问题。 在开发中灵活应用,可以高效构建可靠的 API 服务。