Laravel CORS中间件无法发布帖子和资源请求

时间:2015-11-06 14:57:25

标签: laravel post laravel-5 resources cors

我一直试图解决这个问题一段时间,但无法破解它。

我有一个Laravel后端和角形前端。这些是在不同的领域,因为前端需要是一个网络和移动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',
];
}

8 个答案:

答案 0 :(得分:0)

Seems it has something to do with post request headers after the token is granted to a user. jwt adds in an authorization header and a cookie 在将令牌授予用户之后,它似乎与发布请求标头有关。 jwt添加了授权标题和cookie

答案 1 :(得分:0)

也许您可以使用以下内容暂时解决它:

我在我的控制器构造中添加了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错误。

答案 2 :(得分:0)

现在几个小时都有同样的问题。尝试了不同的解决方案(使用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库也可以工作。没试过。

答案 3 :(得分:0)

在我的情况下,错误是我正在执行在使用jwt进行autenticate之前包含请求的调用。 我有这个导致问题的代码:

vertex.attributes(g)
$name
[1] "2943" "822"  "922"  "1694" "1739" "2891" "1096" "267"  "767"  "839" 
[11] "1348" "350"  "523"  "3641" "1587" "3671" "2666" "2956" "699"  "755"

V(g)[1]
+ 1/20 vertex, named:
[1] 2943

V(g)[V(g)$name == 2943]
+ 1/20 vertex, named:
[1] 2943

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

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);
}

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

答案 4 :(得分:0)

我正面临着类似的事情。在公共目录中编辑.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 :(得分:0)

Cors处理程序是使用此软件包https://github.com/fruitcake/laravel-cors

的最新Laravel版本中的内置功能。

答案 6 :(得分:0)

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

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

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

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

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

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

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

但是没有具有 OPTIONS 方法的路由,resources 也没有 OPTIONS 方法,因此由于没有具有 {{1} 方法的路由} 方法,laravel 不匹配任何内容,因此它不会执行那些您最终处理 OPTIONS 方法的中间件。

<块引用>

OPTIONS 示例

api.php

Laravel 中的匹配函数:

“匹配”函数称为 Route::group(['middleware' => 'cors'], function () { Route::group(['prefix' => 'api'], function() { Route::resources('authenticate', 'AuthenticateController', ['only' => ['index']]); Route::post('authenticate', 'AuthenticateController@authenticate'); }); }); ,它位于 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; } 记录 $route,然后发出 error_log(json_encode($route), 0); 请求,然后查看错误日志时,您可以看到成功的“匹配”并且它应用了 {{1 }} 控制器: 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 请求失败了CORS 错误 (OPTIONS)

总结和解决方案:

  • PUT 数组中的中间件被应用之后 Laravel 成功地将路由与路径和 HTTP 方法匹配,因为不同的路由可以有不同的中间件。
  • Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. 数组中的中间件(全局中间件)在 Laravel 开始注册和匹配路由之前应用

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

答案 7 :(得分:0)

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

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