Вы запустили SPA на React 18, а API живёт на Laravel 11 на другом поддомене. Локально всё работает благодаря proxy, но в продакшене браузер выбрасывает в консоль: «CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource». Знакомая проблема? Без корректной настройки CORS любой запрос с фронтенда к API будет заблокирован. Мы покажем, как решить эту проблему надёжно и безопасно, с учётом реальной инфраструктуры.
Типичная ситуация: фронтенд на Next.js 14 делает POST-запросы с Content-Type: application/json к бэкенду на Django. Без правильной обработки preflight-запроса (OPTIONS) браузер не пропустит основной запрос. Разработчики часто забывают настроить сервер на приём OPTIONS и возврат корректных заголовков. Это приводит к часам отладки и поиска проблемы в неверном месте.
CORS доставляет столько хлопот из-за preflight-запросов, ограничений на wildcard при использовании credentials и необходимости динамической проверки источников. Разберём базовые принципы и перейдём к практике.
Как различаются простые и preflight-запросы?
| Тип запроса | Условия | Preflight |
|---|---|---|
| Простой | HTTP метод GET/POST, Content-Type: form-urlencoded/multipart/form/text | Нет |
| Сложный | Любой другой метод (PUT, DELETE), кастомные заголовки, Content-Type: application/json | Да (OPTIONS) |
Если сервер не отвечает на OPTIONS корректными заголовками, браузер не отправит основной запрос.
Как настроить CORS для нескольких доменов с поддержкой credentials?
Допустим, у вас три фронтенда: продакшен (app.example.com), стейджинг (staging.example.com) и админка (admin.example.com). Access-Control-Allow-Origin: * не подходит, если используются credentials. Решение — динамическая проверка через map в Nginx.
map $http_origin $cors_origin { default ""; ~^(https?://(app|staging|admin)\.example\.com)$ $1; } server { location /api/ { if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin $cors_origin; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With"; add_header Access-Control-Max-Age 86400; return 204; } add_header Access-Control-Allow-Origin $cors_origin always; add_header Access-Control-Allow-Credentials true always; proxy_pass http://backend; } } Такой подход гарантирует, что запросы примутся только с белого списка. В современных версиях Laravel аналогично:
// config/cors.php return [ 'paths' => ['api/*'], 'allowed_methods' => ['*'], 'allowed_origins' => [ 'https://app.example.com', 'https://staging.example.com', 'https://admin.example.com' ], 'allowed_headers' => ['Authorization', 'Content-Type', 'X-Requested-With'], 'exposed_headers' => ['X-Total-Count'], 'max_age' => 86400, 'supports_credentials' => true, ]; Динамическая проверка через map работает в 2 раза быстрее, чем использование регулярных выражений в if-блоке. Это существенно при высоких нагрузках.
Недавно клиент с тремя фронтендами (prod, staging, admin) столкнулся с тем, что API не принимал запросы с Admin-панели. После аудита выяснили: в конфиге стоял Access-Control-Allow-Origin: *, но браузер блокировал credentials. Мы реализовали динамический whitelist через map — проблема решилась за 2 часа. Клиент сэкономил 8 часов самостоятельной отладки.
Почему браузер блокирует запросы с credentials?
Если API использует cookie-сессии или токены в куках, браузер требует:
-
Access-Control-Allow-Credentials: true -
Access-Control-Allow-Originне может быть*— только конкретный домен - На фронтенде
credentials: 'include'(fetch) илиwithCredentials: true(Axios)
Даже если всё настроено, запрос может быть заблокирован, если origin в списке не совпадает по протоколу (HTTP vs HTTPS). Мы гарантируем, что после настройки CORS ваше API будет работать корректно со всеми разрешёнными источниками.
Типичные ошибки и их решения
| Ошибка | Симптом | Исправление |
|---|---|---|
* + credentials |
Preflight проходит, запрос блокируется | Указать точный origin |
| Динамический origin без проверки | CSRF-уязвимость | Использовать whitelist через map |
| Отсутствие CORS-заголовков на 4xx/5xx | Фронтенд не видит тело ошибки | Добавить always в Nginx |
Что входит в работу
- Аудит текущей конфигурации (Nginx/Apache, бэкенд)
- Настройка CORS-заголовков с учётом ваших доменов и методов
- Обработка preflight-запросов
- Поддержка credentials (куки, авторизация)
- Документация по разрешённым источникам и политике
- Тестирование через curl и браузерные инструменты
Процесс работы
- Аналитика — изучаем архитектуру: где живёт фронтенд, какие методы использует, нужны ли куки.
- Проектирование — составляем whitelist origins, список методов и заголовков.
- Реализация — правим конфиг сервера и/или код бэкенда.
- Тестирование — проверяем простые и сложные запросы, credentials, ошибочные ответы.
- Деплой — применяем настройки на продакшен, мониторим логи.
Сроки и стоимость
Базовая настройка CORS для типового проекта занимает от 2 до 4 часов. Для проектов с большим количеством доменов или нестандартными требованиями сроки обсуждаются индивидуально. Стоимость рассчитывается индивидуально в зависимости от сложности инфраструктуры и количества доменов.
Наш опыт — более 7 лет, 50+ проектов с CORS-конфигурацией. Мы поможем избежать типичных ошибок и сэкономим вам время. Закажите настройку — и забудьте о кросс-доменных ошибках. Получите консультацию по вашей конфигурации — напишите, мы поможем.
Документация по CORS на MDN: https://developer.mozilla.org/ru/docs/Web/HTTP/CORS







