Есть несколько хитростей с реализацией поддержки CORS:
Ваше промежуточное ПО CORS должно быть добавлено в глобальный стек промежуточного ПО, поскольку браузер может отправлять запрос Preflight, иВы не хотели бы иметь конкретный маршрут 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.log.bind(console))
Вы должны получить ответ:
{answer: 42}
Не забудьте, что вы должны добавить свои [внешние] маршруты API к routes/api.php
, , а не к routes/web.php
, поскольку в группе веб-маршрутизаторов имеется множество промежуточных программ, которые могут создавать помехи вашим API, например, VerifyCsrfToken
.
MDN: Обмен ресурсами между источниками (CORS)