Yii2 CORS policy: Response to preflight request doesn’t pass access control check почему так?

Ошибка "Response to preflight request doesn't pass access control check" (Предварительный запрос не прошел проверку контроля доступа) возникает, когда клиентский код пытается отправить AJAX-запрос на сервер, который работает на другом домене или на другом порту, и сервер не разрешил такие запросы с помощью политики Access-Control-Allow-Origin.

Политика "Same-Origin" была создана для улучшения безопасности браузера, и ограничивает доступ к ресурсам между разными доменами. Запросы сделанные с одного источника (домена/порта/протокола) могут безопасно делать запросы на тот же самый источник, тогда как запросы сделанные с другого источника требуют дополнительных проверок.

Для разрешения этой ошибки в Yii2 необходимо настроить CORS (Cross-Origin Resource Sharing). Для этого вам понадобится сделать следующие шаги:

1. Создайте специальный класс-фильтр, который будет обрабатывать запросы от разных источников. Например:

namespace appfilters;

use yiibaseActionFilter;

class CorsFilter extends ActionFilter
{
    public function beforeAction($action)
    {
        $allowedOrigins = ['http://example.com', 'http://localhost'];
        
        // проверяем, является ли источник запроса одним из разрешенных
        $origin = Yii::$app->request->getHeaders()->get('Origin');
        if (in_array($origin, $allowedOrigins)) {
            Yii::$app->response->headers->add('Access-Control-Allow-Origin', $origin);
            Yii::$app->response->headers->add('Access-Control-Allow-Credentials', 'true');
        }
        return parent::beforeAction($action);
    }
}

2. Зарегистрируйте созданный фильтр в config/web.php:

return [
    // ...
    'components' => [
        // ...
    ],
    'as cors' => [
        'class' => 'appfiltersCorsFilter',
    ],
    // ...
];

3. Включите CORS-заголовки в настройках вашего web-компонента в config/web.php:

return [
    // ...
    'components' => [
        'response' => [
            'format' => yiiwebResponse::FORMAT_JSON,
            'charset' => 'UTF-8',
            'on beforeSend' => function ($event) {
                $headers = $event->sender->headers;
                $headers->add('Access-Control-Allow-Origin', '*');
                $headers->add('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
                $headers->add('Access-Control-Allow-Headers', 'Accept, Content-Type, X-Requested-With');
                $event->sender->format = yiiwebResponse::FORMAT_JSON;
                return $event->sender;
            },
        ],
        // ...
    ],
    // ...
];

Теперь ваш сервер Yii2 будет разрешать AJAX-запросы от любого источника. Обратите внимание, что во втором шаге вы можете определить список разрешенных источников в allowedOrigins, чтобы ограничить доступ только к определенным источникам.