В ответ не добавлены заголовки Cors

При попытке войти в систему с помощью API (размещенного локально) из приложения React я каждый раз получаю эту ошибку:
В ответ не добавлены заголовки Cors

Я знаю, что есть много тем на эту тему, но ни одна из них не помогла мне. Возможно, потому что я что-то упустил или не понял концепции.

Я больше не знаю, как это исправить.

Вещи, которые я уже пробовал:
- Добавлено промежуточное программное обеспечение 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');

    }
}

Вы делаете это на сервере API, верно?

Styx 15.04.2019 23:28

Да, я @Стикс

Eran Machiels 16.04.2019 08:25

И вы не забыли vendor:publishCorsServiceProvider (в случае spatie/laravel-cors), верно?

Styx 16.04.2019 08:28

@Styx, это действительно сработало. Спасибо! Но знаете ли вы, почему это работает сейчас, а не с промежуточным программным обеспечением, которое я пытаюсь применить? Я не хочу зависеть от внешней зависимости.

Eran Machiels 16.04.2019 10:24

Честно говоря, понятия не имею. Я только что попытался использовать промежуточное ПО ApiCors, используя ваш код, в только что созданном проекте, и он работает, как и ожидалось. Возможно, вы забыли закомментировать VerifyCsrfToken промежуточное ПО или добавить \App\Http\Middleware\ApiCors::class?

Styx 16.04.2019 10:51

Какую версию Laravel вы используете?

Styx 16.04.2019 10:55

Я использую Laravel v5.8.4. Теперь, когда я снова попытался использовать свое собственное промежуточное ПО, оно волшебным образом сработало... Возможно, где-то есть какой-то кеш?

Eran Machiels 16.04.2019 11:02

Ну да, можно запустить php artisan | grep -i clear и посмотреть типы очищаемых кешей.

Styx 16.04.2019 11:05

Да, но, насколько мне известно, ни один из них не кэширует промежуточное ПО. Во всяком случае, это работает. Если бы вы могли опубликовать свой ответ о публикации конфигурации, я могу принять это как ответ.

Eran Machiels 16.04.2019 11:08

Я думаю, что знаю причину этой проблемы, и вы можете испытать ее снова. Я составлю ответ через несколько минут.

Styx 16.04.2019 11:40
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
10
569
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть некоторые сложности с реализацией поддержки CORS:

  1. Ваше промежуточное ПО CORS должно быть добавлено в стек промежуточного ПО Глобальный, потому что браузер может отправить предварительный запрос, и вам не нужно иметь конкретный маршрут OPTIONS для каждого маршрута API.

  2. Программному обеспечению промежуточного слоя не нужно передавать предварительный запрос глубже в приложение.

  3. Заголовки CORS следует добавлять как в предварительные запросы, так и в запросы 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.info.bind(console))

Вы должны получить ответ:

{answer: 42}

Не забывайте, что вы должны добавить свои [внешние] маршруты API в routes/api.php, нет в routes/web.php, потому что в группе веб-маршрутизаторов есть множество промежуточных программ, которые могут мешать вашим API, например, таким как VerifyCsrfToken.

MDN: совместное использование ресурсов между источниками (CORS)

Другие вопросы по теме