При попытке войти в систему с помощью API (размещенного локально) из приложения React я каждый раз получаю эту ошибку:
Я знаю, что есть много тем на эту тему, но ни одна из них не помогла мне. Возможно, потому что я что-то упустил или не понял концепции.
Я больше не знаю, как это исправить.
Вещи, которые я уже пробовал:
- Добавлено промежуточное программное обеспечение 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');
}
}
Да, я @Стикс
И вы не забыли vendor:publishCorsServiceProvider (в случае spatie/laravel-cors), верно?
@Styx, это действительно сработало. Спасибо! Но знаете ли вы, почему это работает сейчас, а не с промежуточным программным обеспечением, которое я пытаюсь применить? Я не хочу зависеть от внешней зависимости.
Честно говоря, понятия не имею. Я только что попытался использовать промежуточное ПО ApiCors, используя ваш код, в только что созданном проекте, и он работает, как и ожидалось. Возможно, вы забыли закомментировать VerifyCsrfToken промежуточное ПО или добавить \App\Http\Middleware\ApiCors::class?
Какую версию Laravel вы используете?
Я использую Laravel v5.8.4. Теперь, когда я снова попытался использовать свое собственное промежуточное ПО, оно волшебным образом сработало... Возможно, где-то есть какой-то кеш?
Ну да, можно запустить php artisan | grep -i clear и посмотреть типы очищаемых кешей.
Да, но, насколько мне известно, ни один из них не кэширует промежуточное ПО. Во всяком случае, это работает. Если бы вы могли опубликовать свой ответ о публикации конфигурации, я могу принять это как ответ.
Я думаю, что знаю причину этой проблемы, и вы можете испытать ее снова. Я составлю ответ через несколько минут.





Есть некоторые сложности с реализацией поддержки CORS:
Ваше промежуточное ПО CORS должно быть добавлено в стек промежуточного ПО Глобальный, потому что браузер может отправить предварительный запрос, и вам не нужно иметь конкретный маршрут OPTIONS для каждого маршрута API.
Программному обеспечению промежуточного слоя не нужно передавать предварительный запрос глубже в приложение.
Заголовки 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)
Вы делаете это на сервере API, верно?