【问题标题】:Laravel 5.1 API Enable CorsLaravel 5.1 API 启用 Cors
【发布时间】:2016-01-09 16:06:43
【问题描述】:

我已经寻找了一些在 laravel 5.1 上启用 cors 的方法,我发现了一些类似的库:

https://github.com/neomerx/cors-illuminate

https://github.com/barryvdh/laravel-cors

但他们都没有专门针对 Laravel 5.1 的实现教程,我尝试配置但它不起作用。

如果有人已经在 laravel 5.1 上实现了 CORS,我将不胜感激...

【问题讨论】:

  • Barryvdh's 适用于 Laravel 5,而且真的应该在 5.1 中开箱即用。你试过了吗?
  • 是的,我试过了,但我仍然收到以下消息(它是一个有角度的前端)XMLHttpRequest 无法加载api.address.com。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin '127.0.0.1:8080' 不允许访问。但是我已经在 cors 文件中添加了本地地址 'supportsCredentials' => true, 'allowedOrigins' => ['127.0.0.1:8080'], 'allowedHeaders' => ['*'], 'allowedMethods' => ['GET' , 'POST', 'PUT', 'DELETE'], 'exposedHeaders' => [], 'maxAge' => 0, 'hosts' => [],
  • 你收到了哪条消息?
  • XMLHttpRequest 无法加载 api.address.com。请求的资源上不存在“Access-Control-Allow-Origin”标头。原点'127.0.0.1:8080';因此不允许访问
  • 您是否发布了配置文件并进行了相应的编辑?

标签: php api laravel cors laravel-5.1


【解决方案1】:

如果您没有通过函数闭包或控制器操作从路由返回响应,那么它将不起作用。

它不工作

控制器动作

Route::post('login','AuthController@login');

class AuthController extends Controller {

     ...

     public function login() {
          dd(['key' => 'value']);
          //OR
          die(['key' => 'value']);
          //OR
          print_r(['key' => 'value');
          exit();
     }

     ...

}

有效!

控制器动作

Route::post('login','AuthController@login');

class AuthController extends Controller {

     ...

     public function login() {
          return response()->json(['key' => 'value'], 200);
          // OR
          return ['key' => 'value'];
          // OR
          $data = ['key' => 'value'];
          return $data;
     }

     ...

}

测试 CORS

Chrome -> 开发者工具 -> 网络标签

如果出现任何问题,那么您的响应标头将不会出现在此处。

【讨论】:

    【解决方案2】:

    Laravel 8

    创建中间件

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    
    class CorsMiddleware
    {
        public function handle(Request $request, Closure $next)
        {
            return $next($request)
                ->header('Access-Control-Allow-Origin', config('cors.allowed_origins')) 
                ->header('Access-Control-Allow-Methods', config('cors.allowed_methods'))
                ->header('Access-Control-Allow-Headers',config('cors.allowed_headers'));
        }
    }
    

    config/cors.php

    return [
        'paths' => [
            'api/*', 
            'admin/api/*', 
            'sanctum/csrf-cookie'
        ],
        'allowed_methods' => [ //'GET, POST, PUT, PATCH, DELETE, OPTIONS'
            'GET', 
            'POST', 
            'PUT', 
            'PATCH', 
            'DELETE', 
            'OPTIONS'
        ],
        'allowed_origins' => ['*'],
        'allowed_origins_patterns' => [],
        'allowed_headers' => [//  'Content-Type, Authorization, Accept'
            'Content-Type', 
            'Authorization', 
            'Accept'
        ],
        'exposed_headers' => [],
        'max_age' => 0,
        'supports_credentials' => true,
    ];
    
    

    kernel.php 用于 http

        protected $middleware = [
            ... ,
            \App\Http\Middleware\CorsMiddleware::class,  // Cors middlewate
        ];
    
    

    【讨论】:

      【解决方案3】:

      这是我的 CORS 中间件:

      <?php namespace App\Http\Middleware;
      
      use Closure;
      
      class CORS {
      
          /**
           * Handle an incoming request.
           *
           * @param  \Illuminate\Http\Request  $request
           * @param  \Closure  $next
           * @return mixed
           */
          public function handle($request, Closure $next)
          {
      
              header("Access-Control-Allow-Origin: *");
      
              // ALLOW OPTIONS METHOD
              $headers = [
                  'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE',
                  'Access-Control-Allow-Headers'=> 'Content-Type, X-Auth-Token, Origin'
              ];
              if($request->getMethod() == "OPTIONS") {
                  // The client-side application can set only headers allowed in Access-Control-Allow-Headers
                  return Response::make('OK', 200, $headers);
              }
      
              $response = $next($request);
              foreach($headers as $key => $value)
                  $response->header($key, $value);
              return $response;
          }
      
      }
      

      要使用 CORS 中间件,您必须先在 app\Http\Kernel.php 文件中注册它,如下所示:

      protected $routeMiddleware = [
              //other middlewares
              'cors' => 'App\Http\Middleware\CORS',
          ];
      

      然后你可以在你的路线中使用它

      Route::get('example', array('middleware' => 'cors', 'uses' => 'ExampleController@dummy'));
      
      编辑:在 Laravel ^8.0 中,您必须导入控制器的命名空间并使用如下类:
      use App\Http\Controllers\ExampleController;
      
      Route::get('example', [ExampleController::class, 'dummy'])->middleware('cors');
      

      【讨论】:

      • 只是为了澄清 - 这是问题中提到的包的替代品吗?
      • @retrograde 是的,如果您选择此解决方案,则不必使用包。
      • 这是非常好的解决方案,也是检查是否允许使用 Origin 的 OPTIONS 方法 - 就像在中间件中一样 - 但由于某种原因,我无法在 laravel 5.X 中为 POST 方法全部运行- 有什么想法吗?
      • 请注意,对我来说它是 5.6 版本,我还需要在 Kernel.php 中的 protected $middleware 数组中添加 \App\Http\Middleware\Cors::class。如果有人像我一样受苦,可以试试这个
      • @arikanmstf 你刚刚完成了我的一周!!这是我在使用 CORS 时遇到的问题。你是对的,将它添加到 kernel.php 中受保护的 $middleware 修复它!非常感谢。
      【解决方案4】:

      https://github.com/fruitcake/laravel-cors

      使用这个库。按照此 repo 中的说明进行操作。

      请记住,不要在 CORS URL 中使用 dd()die(),因为此库将不起作用。始终将 return 与 CORS URL 一起使用。

      谢谢

      【讨论】:

        【解决方案5】:

        对我来说,我将此代码放在public\index.php 文件中。它适用于所有 CRUD 操作。

        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS, post, get');
        header("Access-Control-Max-Age", "3600");
        header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
        header("Access-Control-Allow-Credentials", "true");
        
        

        【讨论】:

          【解决方案6】:

          只需将其用作中间件

          <?php
          
          namespace App\Http\Middleware;
          
          use Closure;
          
          class CorsMiddleware
          {
              /**
               * Handle an incoming request.
               *
               * @param  \Illuminate\Http\Request  $request
               * @param  \Closure  $next
               * @return mixed
               */
              public function handle($request, Closure $next)
              {
                  $response = $next($request);
                  $response->header('Access-Control-Allow-Origin', '*');
                  $response->header('Access-Control-Allow-Methods', '*');
          
                  return $response;
              }
          }
          

          在你的内核文件中注册中间件到这个路径app/Http/Kernel.php你喜欢的组中,一切都会好起来的

          【讨论】:

            【解决方案7】:

            barryvdh/laravel-cors 与 Laravel 5.1 完美配合,只需几个关键点即可启用它。

            1. 将其添加为 Composer 依赖项后,请确保您已发布 CORS 配置文件并根据需要调整 CORS 标头。这是我在 app/config/cors.php

              中的样子
              <?php
              
              return [
              
                  'supportsCredentials' => true,
                  'allowedOrigins' => ['*'],
                  'allowedHeaders' => ['*'],
                  'allowedMethods' => ['GET', 'POST', 'PUT',  'DELETE'],
                  'exposedHeaders' => ['DAV', 'content-length', 'Allow'],
                  'maxAge' => 86400,
                  'hosts' => [],
              ];
              
            2. 在此之后,还有一个文档中没有提到的步骤,您必须在 App 内核中添加 CORS 处理程序'Barryvdh\Cors\HandleCors'。我更喜欢在全局中间件堆栈中使用它。像这样

              /**
               * The application's global HTTP middleware stack.
               *
               * @var array
               */
              protected $middleware = [
                  'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
                  'Illuminate\Cookie\Middleware\EncryptCookies',
                  'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
                  'Illuminate\Session\Middleware\StartSession',
                  'Illuminate\View\Middleware\ShareErrorsFromSession',
              
                  'Barryvdh\Cors\HandleCors',
              
              ];
              

              但您可以将其用作路由中间件并放置在特定路由上。

            这应该使包与 L5.1 一起工作

            【讨论】:

            • 我一直在寻找有关每个配置文件元素的详细信息,尤其是“exposedHeaders”和“supportsCredentials”,但不幸的是还没有成功,您介意提供一些详细信息吗?也许请发布参考?非常感谢!
            【解决方案8】:

            我正在使用 Laravel 5.4,不幸的是,尽管接受的答案似乎很好,但对于预检请求(如 PUTDELETE),其前面将带有 OPTIONS 请求,在 $routeMiddleware 数组中指定中间件(并在路由定义文件中使用它)将不起作用,除非您也为 OPTIONS 定义路由处理程序。这是因为没有 OPTIONS 路由 Laravel 将 internally respond 到没有 CORS 标头的该方法。

            所以简而言之,要么在$middleware 数组中定义中间件,该数组为所有请求全局运行,或者如果你在$middlewareGroups$routeMiddleware 中执行它,那么还为OPTIONS 定义一个路由处理程序。可以这样做:

            Route::match(['options', 'put'], '/route', function () {
                // This will work with the middleware shown in the accepted answer
            })->middleware('cors');
            

            我还为相同的目的编写了一个中间件,它看起来相似但体积更大,因为它试图更具可配置性并处理一堆条件:

            <?php
            
            namespace App\Http\Middleware;
            
            use Closure;
            
            class Cors
            {
                private static $allowedOriginsWhitelist = [
                  'http://localhost:8000'
                ];
            
                // All the headers must be a string
            
                private static $allowedOrigin = '*';
            
                private static $allowedMethods = 'OPTIONS, GET, POST, PUT, PATCH, DELETE';
            
                private static $allowCredentials = 'true';
            
                private static $allowedHeaders = '';
            
                /**
                 * Handle an incoming request.
                 *
                 * @param  \Illuminate\Http\Request  $request
                 * @param  \Closure  $next
                 * @return mixed
                 */
                public function handle($request, Closure $next)
                {
                  if (! $this->isCorsRequest($request))
                  {
                    return $next($request);
                  }
            
                  static::$allowedOrigin = $this->resolveAllowedOrigin($request);
            
                  static::$allowedHeaders = $this->resolveAllowedHeaders($request);
            
                  $headers = [
                    'Access-Control-Allow-Origin'       => static::$allowedOrigin,
                    'Access-Control-Allow-Methods'      => static::$allowedMethods,
                    'Access-Control-Allow-Headers'      => static::$allowedHeaders,
                    'Access-Control-Allow-Credentials'  => static::$allowCredentials,
                  ];
            
                  // For preflighted requests
                  if ($request->getMethod() === 'OPTIONS')
                  {
                    return response('', 200)->withHeaders($headers);
                  }
            
                  $response = $next($request)->withHeaders($headers);
            
                  return $response;
                }
            
                /**
                 * Incoming request is a CORS request if the Origin
                 * header is set and Origin !== Host
                 *
                 * @param  \Illuminate\Http\Request  $request
                 */
                private function isCorsRequest($request)
                {
                  $requestHasOrigin = $request->headers->has('Origin');
            
                  if ($requestHasOrigin)
                  {
                    $origin = $request->headers->get('Origin');
            
                    $host = $request->getSchemeAndHttpHost();
            
                    if ($origin !== $host)
                    {
                      return true;
                    }
                  }
            
                  return false;
                }
            
                /**
                 * Dynamic resolution of allowed origin since we can't
                 * pass multiple domains to the header. The appropriate
                 * domain is set in the Access-Control-Allow-Origin header
                 * only if it is present in the whitelist.
                 *
                 * @param  \Illuminate\Http\Request  $request
                 */
                private function resolveAllowedOrigin($request)
                {
                  $allowedOrigin = static::$allowedOrigin;
            
                  // If origin is in our $allowedOriginsWhitelist
                  // then we send that in Access-Control-Allow-Origin
            
                  $origin = $request->headers->get('Origin');
            
                  if (in_array($origin, static::$allowedOriginsWhitelist))
                  {
                    $allowedOrigin = $origin;
                  }
            
                  return $allowedOrigin;
                }
            
                /**
                 * Take the incoming client request headers
                 * and return. Will be used to pass in Access-Control-Allow-Headers
                 *
                 * @param  \Illuminate\Http\Request  $request
                 */
                private function resolveAllowedHeaders($request)
                {
                  $allowedHeaders = $request->headers->get('Access-Control-Request-Headers');
            
                  return $allowedHeaders;
                }
            }
            

            还为此写了blog post

            【讨论】:

            • 太棒了,我读了你的博客文章,它就像一个魅力。谢谢!
            • @Rishabh 我只是在检查一些与 CORS 相关的 Laravel 问题,几乎每个答案都是一样的,但是这个实际上非常好..
            【解决方案9】:

            我总是使用简单的方法。只需在\public\index.php 文件中添加以下行。我认为您不必使用中间件。

            header('Access-Control-Allow-Origin: *');  
            header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
            

            【讨论】:

            • 不优雅
            • @EfriandikaPratama 为什么不呢? index.php 文件正在用于所有 HTTP 请求。所以这是一种简单且用户友好的方式。
            • @EfriandikaPratama 一遍又一遍地说同样的话并不能证明你的观点。
            • 如果您想为您的整个应用启用 CORS,这很好,但如果您想在某些路由上启用 CORS,则不适用。我认为使用中间件更有意义。
            • 这很简短,我认为当所有路由都已使用 OAuth 或 JWT 保护时,不需要在中间件中进行保护。
            猜你喜欢
            • 2015-02-19
            • 2019-04-17
            • 2015-02-19
            • 2018-12-03
            • 2014-12-04
            • 1970-01-01
            • 2023-03-30
            • 2016-05-28
            相关资源
            最近更新 更多