Ви запустили 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







