Laravel/React: barryvdh/laravel-cors обрабатывает предварительный HTTP-запрос OPTIONS

Только начинаем с barryvdh/laravel-cors. У меня есть приложение на стороне сервера, работающее на порту 8000, которое аутентифицирует пользователей через Laravel Passport, и мое клиентское приложение react.js, работающее на порту 3000. Сейчас я пытаюсь заставить работать действие «вход».

От клиента, когда я предоставляю правильные учетные данные, токен отправляется обратно, и статус равен 200. Если учетные данные недействительны, возвращается 401. Так хорошо до сих пор. Однако, если я укажу только адрес электронной почты в форме и не укажу пароль, я получу следующую ошибку, связанную с CORS:

Laravel/React: barryvdh/laravel-cors обрабатывает предварительный HTTP-запрос OPTIONS

При возникновении ошибки происходят следующие сетевые вызовы:

Laravel/React: barryvdh/laravel-cors обрабатывает предварительный HTTP-запрос OPTIONS

Мой логин на стороне клиента:

login = (email, password) => {
    console.info(email);
    fetch("http://localhost:8000/api/auth/login", {
        method: 'POST',
        body: JSON.stringify({
            'email': email,
            'password': password
        }),
        headers: {
            'Content-Type': 'application/json'
        }
    })
    .then(res => res.json())
    .then(response => {
        console.info(response['access_token']); //with correct credentials this is logged out and set in local storage
        localStorage.setItem('access_token', response['access_token']);
    })
    .catch(error => console.error('Error: ', error));
}

Сторона сервера:

public function login(Request $request)
{
    $request->validate([
        'email' => 'required|string|email',
        'password' => 'required|string',
        'remember_me' => 'boolean'
    ]);

    $credentials = request(['email', 'password']);

    if (!Auth::attempt($credentials)) {
        return response()->json([
            'message' => 'Unauthorized'
        ], 401);
    }

    $user = $request->user();
    $tokenResult = $user->createToken('Personal Access Token');
    $token = $tokenResult->token;

    if ($request->remember_me) {
        $token->expires_at = Carbon::now()->addWeeks(1);
    }

    $token->save();
    return response()->json([
        'access_token' => $tokenResult->accessToken,
        'token_type' => 'Bearer',
        'expires_at' => Carbon::parse(
            $tokenResult->token->expires_at
        )->toDateTimeString()
    ]);
}

cors.php (опубликовано из пакета barryvdh/laravel-cors):

return [
    'supportsCredentials' => false,
    'allowedOrigins' => ['*'],
    'allowedOriginsPatterns' => [],
    'allowedHeaders' => ['*'],
    'allowedMethods' => ['*'],
    'exposedHeaders' => [],
    'maxAge' => 0,
];

api.php:

Route::group(['prefix' => 'auth',], function () {
    Route::post('login', 'AuthController@login');
    Route::post('register', 'AuthController@register');
    Route::get('register/activate/{token}', 'AuthController@registerActivate');
    Route::group(['middleware' => 'auth:api'], function() {
        Route::get('logout', 'AuthController@logout');
        Route::get('user', 'AuthController@user');
    });
});

Kernel.php:

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        \Barryvdh\Cors\HandleCors::class,
        'throttle:60,1',
        'bindings',
    ],
];

protected $middleware = [
    \Barryvdh\Cors\HandleCors::class,
    \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
];

Выполняя тот же запрос POST (один к /api/auth/login с исключенным паролем) через почтальона, я получаю ожидаемое сообщение об ошибке:

{
    "message": "The given data was invalid.",
    "errors": {
        "password": [
            "The password field is required."
        ]
    }
}

Но, делая это через клиентское приложение реакции, выдается ошибка на скриншоте. Я предполагаю, что это как-то связано с предварительным HTTP-запросом OPTIONS, который браузер отправляет как часть работы CORS.

Как я могу это исправить? Я ожидаю, что для статуса будет возвращено 401, а реагирующий клиент получит то же сообщение JSON, которое Почтальон получает в случае, если пароль пуст. Просто кажется странным, что на основе полезной нагрузки для этого запроса POST возникает ошибка, связанная с CORS. Означает ли это, что сервер и/или клиент неправильно настраивают CORS?

И приложение laravel, и приложение react должны правильно отправлять заголовки CORS. Если вы можете избежать перенаправлений CORS, с этим будет намного проще справляться.

apokryfos 08.04.2019 03:01

Я думал, что только на стороне сервера нужно установить заголовки, связанные с CORS. Какие заголовки нужно установить на стороне клиента? Я не думаю, что смогу избежать перенаправления CORS

Chris 13.04.2019 20:52

Реагирующее приложение, похоже, обслуживается с другого сервера, где есть localhost: 3000 и localhost: 8000, к которым клиент обращается, поэтому им обоим нужны заголовки CORS.

apokryfos 13.04.2019 21:00

можете ли вы добавить свою конфигурацию CORS для бэкэнда в вопросе?

Abdelkarim EL AMEL 14.04.2019 23:29

Добавлен. Я должен был опубликовать это раньше - я не совсем уверен, что правильно настроил эту часть. Я думаю, что у меня есть просто настройки конфигурации по умолчанию из пакета barryvdh/laravel-cors

Chris 14.04.2019 23:35

вы выполнили команду php artisan vendor:publish --provider = "Barryvdh\Cors\ServiceProvider" ?

Abdelkarim EL AMEL 14.04.2019 23:52

да. вот откуда взялся cors.php

Chris 15.04.2019 00:02

на данный момент кажется отличным, не могли бы вы также добавить config/app.php контент и раздел промежуточного программного обеспечения в свой Kernel.php?

Abdelkarim EL AMEL 15.04.2019 00:12

Ничего не изменилось в app.php относительно пакета cors, должны ли там быть изменения? выложу kernel.php

Chris 15.04.2019 00:44

могу я спросить, зачем нужны разные порты?

Ronald 15.04.2019 05:34

Я использую разные порты для разработки, поскольку, когда я фактически развертываю это приложение в целом, API Laravel будет обслуживаться веб-сервером Nginx, а приложение React будет обслуживаться через node. По сути, я пытаюсь сохранить полное разделение между клиентом и сервером — надеюсь, это имеет смысл.

Chris 15.04.2019 05:38

@Ronald, просто чтобы уточнить: используются разные порты, потому что локально у меня работают 2 сервера. Один обслуживает php-приложение, а другой обслуживает реагирующее приложение.

Chris 15.04.2019 05:49

я вижу, что \Barryvdh\Cors\HandleCors::class, объявлен как в $middleware, так и в $middlewareGroups, можете ли вы попробовать удалить его из раздела $middlewareGroups, и еще одна вещь, я заметил, что у многих людей есть эта проблема, и она, похоже, связана с версией пакета, какая версия ты используешь ? Взгляните на эти проблемы: ссылка1, ссылка2

Abdelkarim EL AMEL 15.04.2019 10:08

Я попытался удалить запись в $middlewareGroups - похоже, это не имеет значения. Я использую последнюю версию (0.11.3). Я думаю, что нашел проблему - на стороне сервера мне требуется пароль (при вызове $request->validate(...)), когда эта проверка не проходит (из-за того, что клиент не предоставляет пароль), кажется, что промежуточное программное обеспечение CORS не полностью работает - это тут же проваливается. Изменение этого поля на необязательное на стороне сервера (что, конечно, не очень хорошая идея) приводит к возврату 401, когда пароль не указан (поэтому неверная комбинация пользователя/пароля)

Chris 16.04.2019 02:49

@AbdelkarimELAMEL, вы должны поместить свои комментарии в качестве ответа, в частности, вторую ссылку, которую вы предоставили, и информацию github о том, что «при возникновении ошибки промежуточное программное обеспечение не запускается полностью». В этом была проблема. Я просто не видел этого в репо и не ожидал ошибки, связанной с CORS. Спасибо за вашу помощь

Chris 16.04.2019 02:58

Пожалуйста, я добавлю это как ответ.

Abdelkarim EL AMEL 16.04.2019 10:11
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
16
1 414
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Прежде всего член класса:

protected $middleware

Применит промежуточное ПО как для api, так и для web

Отlaravel.com/docs/5.8/middleware#registering-middleware

If you want a middleware to run during every HTTP request to your application, list the middleware class in the $middleware property of your app/Http/Kernel.php class.

Смотрите также:barryvdh/laravel-cors#глобальное использование

Поэтому попробуйте зарегистрировать свое промежуточное ПО один раз, удалив: \Barryvdh\Cors\HandleCors::class из ваших 'api'группа промежуточного программного обеспечения.

И для логических целей рефакторинг вашего protected $middleware с помощью:

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,
    \Barryvdh\Cors\HandleCors::class,
];
Ответ принят как подходящий

Кажется, что ошибка возникает, когда ошибка возникает в вашем бэкэнде.

Как указано в документы :

When an error occurs, the middleware isn't run completely. So when this happens, you won't see the actual result, but will get a CORS error instead.

Этот проблема помог выяснить источник ошибки

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