【问题标题】:Laravel CORS middleware fails for post and resource requestLaravel CORS 中间件无法用于发布和资源请求
【发布时间】:2016-02-07 18:20:00
【问题描述】:

我一直在尝试解决这个问题,但无法破解它。

我有一个 Laravel 后端和 Angular 前端。它们位于不同的域中,因为前端需要是 Web 和移动 Cordova 应用程序。

即使添加了 CORS 中间件,帖子和资源请求也无法加载,我得到了一个

No 'Access-Control-Allow-Origin' header is present on the requested resource

控制台出错。

以下获取请求确实可以正常工作:-

Route::get('example', ['middleware' => 'cors', function(){
    return Response::json(array('name' => 'Steve Jobs 1', 'company' => 'Apple'));
}]);

但是后面的失败了 -

Route::group(['middleware' => 'cors'], function () {
Route::group(['prefix' => 'api'], function()
{
    Route::resources('authenticate', 'AuthenticateController', ['only' => ['index']]);
    Route::post('authenticate', 'AuthenticateController@authenticate');
});
});

我关注https://scotch.io/tutorials/token-based-authentication-for-angularjs-and-laravel-apps

我的 CORS.php

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;
    return $next($request);
}
}

kernel.php

class Kernel extends HttpKernel
{

protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \App\Http\Middleware\EncryptCookies::class,
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    /*\App\Http\Middleware\VerifyCsrfToken::class,*/
];


protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
    'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
    'cors' => 'App\Http\Middleware\CORS',
];
}

【问题讨论】:

  • 您能发布您的请求返回的 HTTP 响应代码吗?我最近遇到了类似的问题,我的回复返回了 500 的代码,这是一个内部服务器错误。原来这与我的标题无关,而是我没有正确执行 CSRF。禁用 CSRF 使其工作。也许尝试一下,看看它是否真的是一个 CORS 问题或其他类似的问题?
  • 好的,我知道你在哪里禁用了 CSRF,所以不是那样的。不过,了解 HTTP 响应代码可以提供一些见解。

标签: laravel post laravel-5 resources cors


【解决方案1】:

对于 cors,我建议使用这个包。 https://github.com/fruitcake/laravel-cors

但是,如果您有大量请求。最好在 nginx 或 apache 级别配置 cors。会有 nginx 比 php-fpm 可以处理大量的请求,所以会优化性能。

【讨论】:

    【解决方案2】:

    因此,当我在 api.php 中使用自己的 CORS 中间件而不使用水果蛋糕 (barryvdh/laravel-cors) 时,我遇到了同样的问题并花了数小时调试并找出问题所在。

    经过数小时的调试和挫折后,我发现当您在组中使用中间件时,它不会立即得到应用。

    laravel 如何匹配路由并“应用”中间件:

    当您发送请求时,laravel 会读取 api.php 并“注册”所有路由和中间件并“记住”它们而不实际执行它们。在它“注册”所有这些之后(读取整个 api.php 文件),它执行一个函数,在该函数中输入来自 URL 的路径和请求中使用的 HTTP 方法,然后开始查找匹配的路由URL 和 HTTP 方法,找到一个后,它会执行该路由所在的那些中间件,然后执行控制器方法。

    例如,当您向/api/authenticate 发送GET 请求时,您的代码会匹配资源方法index,然后执行中间件cors,因此它可以工作并从您的控制器返回数据。

    为什么 POST、PUT、DELETE 和 PATCH 不适用于这种方法:

    当你向/api/authenticate发送POSTPUTDELETEPATCH请求时,浏览器会先发送OPTIONS请求,所以laravel“注册”所有路由然后执行使用 URL 和 HTTP 方法的“匹配”(现在是 OPTIONS)。

    但是没有路由有OPTIONSresources 也没有OPTIONS 方法,所以由于没有路由有OPTIONS 方法,所以laravel 不匹配任何东西,因此它不会执行您最终处理 OPTIONS 方法的那些中间件。

    api.php 示例

    Route::group(['middleware' => 'cors'], function () {
      Route::group(['prefix' => 'api'], function() {
         Route::resources('authenticate', 'AuthenticateController', ['only' => ['index']]);
         Route::post('authenticate', 'AuthenticateController@authenticate');
      });
    });
    

    Laravel 中的匹配函数:

    “匹配”函数名为findRoute,位于vendor/laravel/framework/src/Illuminate/Routing/Router.php

    /**
     * Find the route matching a given request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Routing\Route
     */
    protected function findRoute($request)
    {
        $this->current = $route = $this->routes->match($request);
    
        $this->container->instance(Route::class, $route);
    
        return $route;
    }
    

    当您使用error_log(json_encode($route), 0); 记录$route,然后发出GET 请求,然后查看错误日志,您可以看到成功的“匹配”并且它应用了cors 控制器: {"uri":"api\/authenticate","methods":["GET","HEAD"],"action":{"middleware":["cors"],"uses":"App\\Http\\Controllers\\AuthenticateController@index","controller":"App\\Http\\Controllers\\AuthenticateController@index","namespace":null,"prefix":"api","where":[]},"isFallback":false,"controller":null,"defaults":[],"wheres":[],"parameters":[],"parameterNames":[],"computedMiddleware":null,"compiled":{}}

    但是当您发送PUT 请求时,会发生这种情况: {"uri":"api\/authenticate","methods":["OPTIONS"],"action":{"uses":{}},"isFallback":false,"controller":null,"defaults":[],"wheres":[],"parameters":[],"parameterNames":[],"computedMiddleware":null,"compiled":{}}

    您可以看到实际上发送了OPTIONS 方法(因为浏览器首先发送OPTIONS 方法)并且没有匹配到任何中间件,因此PUT 请求失败并出现CORS 错误(@987654354 @)

    总结及解决办法:

    • $routeMiddleware 数组中的中间件被应用之后 Laravel 成功地将路由与路径和 HTTP 方法匹配,因为不同的路由可以有不同的中间件。
    • $middleware 数组中的中间件(全局中间件) Laravel 开始注册和匹配路由之前得到应用。

    要解决这个问题,您必须$middleware 数组中使用一个全局中间件,该中间件处理OPTIONS 方法。您可以只使用处理它的Fruitcake,然后您可以在api.php 中使用您自己的 CORS 中间件,可以根据自己的喜好设置不同的标头(例如,不同路由/组/前缀的不同允许来源。

    【讨论】:

      【解决方案3】:

      Cors 处理程序是使用此包 https://github.com/fruitcake/laravel-cors 的最新 Laravel 版本中的内置功能

      【讨论】:

        【解决方案4】:

        我面临着类似的事情。在我编辑公共目录中的 .htaccess 文件后,它工作得很好。下面是htaccess文件:

        <IfModule mod_rewrite.c>
            <IfModule mod_negotiation.c>
                Options -MultiViews -Indexes
            </IfModule>
        
            RewriteEngine On
            Header set Access-Control-Allow-Origin "*"
            Header set Access-Control-Allow-Headers "Authorization"
            # Handle Authorization Header
            RewriteCond %{HTTP:Authorization} .
            RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
        
            # Redirect Trailing Slashes If Not A Folder...
            RewriteCond %{REQUEST_FILENAME} !-d
            RewriteCond %{REQUEST_URI} (.+)/$
            RewriteRule ^ %1 [L,R=301]
        
            # Send Requests To Front Controller...
            RewriteCond %{REQUEST_FILENAME} !-d
            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteRule ^ index.php [L]
        </IfModule>
        

        让我知道此解决方案是否适合您

        确保通过运行在 htaccess 中启用标头

        sudo a2enmod headers 
        

        【讨论】:

          【解决方案5】:

          在我的情况下,错误是我在使用 jwt 进行身份验证之前执行了包含请求的调用。 我有导致问题的代码:

          function store(Request $request)
          {
              $producto = new Producto($request->json()->all());
              $this->currentUser = JWTAuth::parseToken()->authenticate();
              $producto->cliente_id = $this->currentUser->cliente_id;
              $producto->save();
              return json_encode($producto);
          }
          

          如您所见,JWTAuth 行位于使用 $request 的行之前。 您可以将 JWTAuth 行移动到函数中的 forst 行,或者在类中创建一个构造函数,如下所示:

          function __construct() {
              $this->currentUser = JWTAuth::parseToken()->authenticate();
          }
          

          这解决了 cors 问题。 我使用 Barryvdh Cors。

          【讨论】:

            【解决方案6】:

            几个小时以来一直遇到同样的问题。尝试了不同的解决方案(使用了barryvdh/laravel-cors library,制作了我自己的 CORS 中间件,在 index.php 文件中添加了标题)但没有任何帮助。

            现在我正在使用https://github.com/neomerx/cors-illuminate,它可以工作。

            cors-illuminate 库和 laravel-cors 库之间的区别之一在于安装指南。 在 cors-illuminate 指南中,它明确表示您必须直接在之后添加中间件行

            \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
            

            如果您直接在 CheckForMaintenanceMode 中间件之后添加中间件,也许 laravel-cors 库也可以工作。没试过。

            【讨论】:

              【解决方案7】:

              也许您可以使用以下方法暂时绕过它:

              我在控制器结构中添加了 cors 中间件,如下所示:

                    public function __construct()
                 {
                     // Apply the jwt.auth middleware to all methods in this controller
                     // except for the index method.
                     $this->middleware('jwt.auth', ['except' => ['index']]);
                     $this->middleware('cors');
              
                 }
              

              在我的内核中:

                  protected $routeMiddleware = [
                  'auth' => \App\Http\Middleware\Authenticate::class,
                  'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
                  'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
              
                  'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
                  'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
                  'cors'=> \Barryvdh\Cors\HandleCors::class
              
              
              ];
              

              这似乎对我有用。另外,检查你的 laravel 日志并调试你的控制器。我的控制器中有错字,客户端控制台中的 http 响应是 cors 错误。

              【讨论】:

              • 你检查你的 storage/logs/laravel.log 了吗?因为如果您的控制器中有任何语法错误,客户端消息仍然会说:(索引):1 XMLHttpRequest 无法加载localhost:8000/api/v1/partner。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin 'localhost:9001' 不允许访问。响应的 HTTP 状态代码为 500。
              【解决方案8】:

              在将令牌授予用户后,它似乎与发布请求标头有关。 jwt 添加了一个授权头和一个 cookie

              【讨论】:

                猜你喜欢
                • 2016-10-18
                • 2019-11-24
                • 2018-09-18
                • 2015-10-14
                • 2020-09-26
                • 2018-08-07
                • 2011-08-10
                相关资源
                最近更新 更多