Laravel 5.2 CORS,GET 无法使用预检选项

Laravel 5.2 CORS, GET not working with preflight OPTIONS

可怕的 CORS 错误:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/mysite/api/test. (Reason: CORS header 'Access-Control-Allow-Origin' missing).

Laravel 路线:

$router->group(['prefix' => 'api', 'middleware' => 'cors'], function ($router) {
    $router->get('/test', 'MyController@myMethod');
});

Laravel Cors 中间件:

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, Authorization'
        ];
        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;
    }

Laravel 内核:

 protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'cors' => \App\Http\Middleware\CORS::class
    ];

相关.htaccess:

RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

相关Vue.js:

 new Vue({
        el: '#app',
        data: {
           //data here
        },
        http: {
            headers: {
                "Authorization": "Basic " + "apiKeyHere"
            }
        },
        methods: {
            mymethod: function (e)
            {
                e.preventDefault();
                this.$http.get('http://localhost/mysite/api/test').then(
                        function (response)
                        {
                          //do something
                        }
                )
            }
        }
    });

如果我取消授权 header 选项,请求就会生效。

我也试过 https://github.com/barryvdh/laravel-cors 但还是不满意。 感谢任何帮助!

显然不是理想的解决方案,但它确实有效。我已将此添加到我的 routes.php 文件的顶部:

header('Access-Control-Allow-Origin: *');
header( 'Access-Control-Allow-Headers: Authorization, Content-Type' );

如果没有破解就可以正常工作了……唉。

更新:原来是IIS相关的。我最终在 web.config 文件中设置了 headers,现在 CORS 可以在不破解 routes.php 文件的情况下工作。

<httpProtocol>
    <customHeaders>
       <add name="Access-Control-Allow-Headers" value="Origin, Authorization, X-Requested-With, Content-Type, Accept" />
       <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS,PUT,DELETE" />
    </customHeaders>
</httpProtocol>

如果要限制访问,可以添加出站规则:

      <outboundRules>
          <clear />
                <rule name="AddCrossDomainHeader">
                    <match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                        <add input="{HTTP_ORIGIN}" pattern="(http(s)?://((.+\.)?somesite\.com|(.+\.)?anothersite\.org))" />
                    </conditions>
                    <action type="Rewrite" value="{C:0}" />
                </rule>
      </outboundRules>

我解决了我的问题,只是在我的 routes.php Laravel 5.2 中添加了这些行 在 routes/web.php

中大于 5.2
header('Access-Control-Allow-Origin:  *');
header('Access-Control-Allow-Methods:  POST, GET, OPTIONS, PUT, DELETE');
header('Access-Control-Allow-Headers:  Content-Type, X-Auth-Token, Origin, Authorization');

或在全局 HTTP 中间件堆栈中注册 Cors 中间件

protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \App\Http\Middleware\CorsMiddleware::class
];

Laravel 7 或更低:

你的中间件没问题,但你需要在全局 HTTP 中间件堆栈中注册 Cors 中间件。

protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \App\Http\Middleware\CorsMiddleware::class
];

Laravel 8 或更高:

All CORS settings may be configured in your application's config/cors.php configuration file. The OPTIONS requests will automatically be handled by the HandleCors middleware that is included by default in your global middleware stack.

Link到官方documentation

你可以绕过这个而不使用任何中间件,比如 Barryvdh\Cors for Laravel 它不能与 JWT AUTH 一起正常工作,我在 index.php 中添加了以下语句 Laravel 就在内核实例化之前

header('Access-Control-Allow-Origin: http://localhost:8001');
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token,Authorization');
header('Access-Control-Allow-Credentials: true');

在前面加上这个

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

这也应该与 JWT AUTH 一起正常工作。 请注意,在 Access-Control-Allow-Headers 中您应该包含 Authorization 否则您的 accesstoken 将不允许使用 Authorization header 因此 JWT AUTH 将失败。 快乐编码。

确实,问题是由预检请求引起的,但是处理方式需要一些额外的解释,当我们谈论 Laravel - 主要是 OPTIONS 请求被路由(其他的东西答案宁愿做 PHP 方式,而不是 Laravel 方式),所以,你必须将它添加到你的路线才能成功:

Route::options('/{any}', function(){ return ''; })->where('any', '.*');

现在,让我们满足所有其他方法 - 创建 CORS 中间件:

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)
    {
        return $next($request)
            ->header('Access-Control-Allow-Origin', '*')
            ->header('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, DELETE');
    }
}

最后,对于给定的路由,使用该中间件:

Route::put('/test', function(){ echo('test'); })->with('cors');

此答案基于此articlebarryvdh/laravel-cors中间件库,可用于修复问题(Cross-Origin资源共享)。

步骤 1 安装:

composer require barryvdh/laravel-cors

步骤 2 发布库的供应商文件:

php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider"

步骤 3 步骤 2 中的命令 运行 将复制一个 cors.php 文件到配置目录,如下所示:

return [

/*
|--------------------------------------------------------------------------
| Laravel CORS
|--------------------------------------------------------------------------
|
| allowedOrigins, allowedHeaders and allowedMethods can be set to array('*')
| to accept any value.
|
*/

'supportsCredentials' => false,
'allowedOrigins' => ['*'],// ex: ['abc.com', 'api.abc.com']
'allowedHeaders' => ['*'],
'allowedMethods' => ['*'],// ex: ['GET', 'POST', 'PUT', 'DELETE']
'exposedHeaders' => [],
'maxAge' => 0,

];

对于 allowedOrigins,值可以是 ['*'],表示请求的来源可以来自任何域,或者是一组特定域,它们可以是我们将允许的来源向我们的 api 发送请求,像这样 ['first.com', 'second.com', 'register.third.com']

并且 allowedMethods 可以是 ['*'] 或允许的列表 HTTP verbs 例如 ['POST', 'GET']

步骤 4 注册 cors 中间件。打开 app/Http/kernel.php 并将 HandleCors class 添加到 $routeMiddleware,如下所示:

protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'cors' => \Barryvdh\Cors\HandleCors::class, // add this line to enable cors to your routes
];

步骤 5 现在您可以将 laravel-cors 中间件添加到您想要的任何路由。例如在 Routes/api.php 我会这样做:

Route::apiResource('category', 'CategoryController')->middleware('cors');
Route::apiResource('product', 'ProductController')->middleware('cors');

我的解决方案:

$router->group(['prefix' => 'api', 'middleware' => 'cors'], function ($router){
    $router->options('{param1?}/{param2?}/{param3?}', function () {});
});

即使将你的中间件直接放入 $middleware 而不是 $routeMiddleware 或简单地在 app.php 中全局定义 headers,这也是一个可怕的决定,因为它将使用新的 CORS 策略公开所有端点,以防您只想将 API public 的一部分提供给第三方解决方案。

更好的解决方案是只允许 OPTIONS 调用在所有端点上通过,并且仍然通过 $routeMiddleware 重定向其他 HTTP 方法,以便能够仅在端点的子集上限制 CORS 策略。

所以,构建两个中间件:

Cors.php

 <?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)
    {
        return $next($request)
          ->header('Access-Control-Allow-Origin', '*')
          ->header('Access-Control-Allow-Methods', '*')
          ->header('Access-Control-Allow-Headers', '*');
    }
}

选项Cors.php

<?php

namespace App\Http\Middleware;

use Closure;

class OptionsCors
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
      if($request->isMethod('OPTIONS')) {
        return $next($request)
          ->header('Access-Control-Allow-Origin', '*')
          ->header('Access-Control-Allow-Methods', '*')
          ->header('Access-Control-Allow-Headers', '*');
      }
      return $next($request);
    }
}

app/Http/Kernel.php

<?php 
namespace App\Http
{
    class Kernel extends \Illuminate\Foundation\Http\Kernel
    {
        protected $middleware = [
            // ...
            'App\Http\Middleware\OptionsCors',
        ];
        protected $middlewareGroups = [
            'web' => [
                 // ...
            ], 
            'api' => [
                'App\Http\Middleware\UseApiGuard', 
                'throttle:60,1', 
                'bindings'
            ]
        ];
        protected $routeMiddleware = [
            // ...
            'cors' => 'App\Http\Middleware\Cors', 
        ];
    }

}

现在,在您的路由中,您可以完全控制通过收紧的 CORS 策略公开哪些端点:

Route::namespace('Api')->middleware(['cors'])->group(function () {

    Route::get('api/im_open', 'TestController@ping');

});
Route::namespace('Api')->group(function () {

    Route::get('api/im_closed', 'TestController@ping');

});

我通过在bootstrap/app中添加headers轻松解决了我的问题。php

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: *');
header('Access-Control-Allow-Headers: *');