未向响应添加Cors标头

时间:2019-04-15 20:30:21

标签: reactjs laravel api cors axios

当尝试使用来自React应用程序的API(本地托管)登录时,每次都会出现此错误:
Error image

我知道这个领域有很多主题,但是没有一个对我有帮助。也许是因为我错过了一些东西,或者是不了解这个概念。

我不知道如何解决此问题。

我已经尝试过的事情
-添加了HTTP中间件(将跟随代码):无效。
-尝试使用spatie/laravel-cors软件包进行修复:无效。
-尝试使用barryvdh/laravel-cors进行修复:也不起作用。

我没主意了。有人知道我在做什么错吗?

我的代码

protected $middleware = [
    \App\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    \App\Http\Middleware\TrustProxies::class,
    \Spatie\Cors\Cors::class, // <-- this line would be pointed to my own middleware when that would be in use
];

如果我要使用自己的中间件,则指向以下代码而不是\Spatie\Cors\Cors::class

class ApiCors
{
    /**
     * 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, PUT, DELETE, OPTIONS, PATCH')
            ->header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');

    }
}

1 个答案:

答案 0 :(得分:0)

实施CORS支持有些棘手的事情:

  1. 您的CORS中间件应添加到 global 中间件堆栈中,因为浏览器可以发送Preflight请求,并且您不希望每个API路由都有特定的OPTIONS路由

  2. 中间件不需要将预检请求更深地传递给应用程序。

  3. CORS标头应同时添加到Preflight请求和API请求中。

因此,应该这样做:

创建中间件:

php artisan make:middleware ApiCors

输入代码:

<?php

namespace App\Http\Middleware;

use Closure;

class ApiCors {

  /**
   * Handle an incoming request.
   *
   * @param  \Illuminate\Http\Request $request
   * @param  \Closure $next
   *
   * @return mixed
   */
  public function handle($request, Closure $next)
  {
    $isPreflight = $request->isMethod('options') && $request->hasHeader('origin');

    // we don't need to process Preflight request further
    $response = $isPreflight ? response()->make() : $next($request);

    if($isPreflight) {
      $response
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH')
        ->header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')
        ->header('Access-Control-Max-Age', 86400);
    }
    $response->header('Access-Control-Allow-Origin', $isPreflight ? '*' : ($request->header('origin') ?? '*'));

    return $response;
  }
}

注册中间件:

app/Http/Kernel.php

<?php
// ...
use App\Http\Middleware\ApiCors;

class Kernel extends HttpKernel {
  // ...
  protected $middleware = [
    // ...
    ApiCors::class,
  ];
  // ...
  protected $middlewarePriority = [
    ApiCors::class, // move to the top of the chain
    // ...
  ];
}

测试中间件:

让我们添加简单的API路由。

routes/api.php

Route::put('/v1/test', function () {
  return response()->json(['answer' => 42]);
});

让我们启动简单服务器(在Laravel项目根文件夹中运行):

php -S localhost:8088 -t public

下一步,打开任何网页(或使用当前网页)并在开发者控制台中运行:

fetch('http://localhost:8088/api/v1/test', {
  method: 'PUT', headers: { 'accept': 'application/json' }
}).then(r => r.json()).then(console.log.bind(console))

您应该得到答复:

{answer: 42}

请不要忘记将[外部] API路由添加到routes/api.php,将 not 添加到routes/web.php,因为Web路由器组有许多中间件,它们可能会干扰与您的api一起使用,例如VerifyCsrfToken

MDN: Cross-Origin Resource Sharing (CORS)