Посібники

Як виправити помилки CORS (і чому вони виникають)

Помилка CORS означає, що ваша веб-сторінка намагалася прочитати відповідь з іншого origin (іншого домену, порту або протоколу), а сервер не надіслав заголовків, які це дозволяють. Браузери блокують відповідь, щоб захистити користувачів. Виправляють це на сервері: повертаючи заголовок Access-Control-Allow-Origin для origin вашого сайту та обробляючи OPTIONS-запити preflight, або обходять проблему, надсилаючи запит через власний бекенд на тому самому origin.

Це одна з найзаплутаніших помилок у веб-розробці, бо запит часто доходить до сервера без проблем. Цей посібник пояснює, що відбувається, і як виправити кожен варіант.

Що означає «origin»

Origin — це поєднання протоколу, домену та порту:

URLOrigin
https://myapp.com/dashboardhttps://myapp.com
https://api.myapp.com/usershttps://api.myapp.com (інший піддомен, тобто інший origin)
http://localhost:5173http://localhost:5173
http://localhost:3000http://localhost:3000 (інший порт, тобто інший origin)

Браузери дотримуються same-origin policy (політики одного походження): JavaScript на сторінці може вільно читати відповіді зі свого origin, але не з інших. CORS (Cross-Origin Resource Sharing, спільний доступ до ресурсів між різними джерелами) — це механізм, який дозволяє серверу свідомо погодитися: «відповіді від мене можуть читати сторінки з цих origin».

Два наслідки часто дивують:

  • Запит часто доходить до сервера. CORS зазвичай блокує вашому коду читання відповіді, а не отримання запиту сервером. POST могло зберегтися, навіть якщо ви побачили помилку.
  • CORS застосовують лише браузери. curl, Postman і серверний код його ігнорують. Тому «працює в Postman» нічого не говорить про CORS.

Крок 1: Прочитайте точний текст помилки

Відкрийте інструменти розробника (правий клік → Inspect, «Перевірити»), перейдіть на вкладку Console і прочитайте повне повідомлення. Формулювання Chrome показує, яка саме проблема:

Повідомлення міститьЩо не так
No 'Access-Control-Allow-Origin' header is presentСервер не надіслав заголовок взагалі, або запит впав ще до вашого коду CORS (наприклад, 404 чи 500)
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied originСервер дозволяє інший origin, ніж ваш
Response to preflight request doesn't pass access control checkПопередній запит OPTIONS (preflight) не пройшов перевірку
...must not be the wildcard '*' when the request's credentials mode is 'include'Ви надсилаєте cookies, а сервер відповів *
Request header field authorization is not allowedСервер не додав цей заголовок до Access-Control-Allow-Headers

Потім відкрийте вкладку Network (Мережа), знайдіть запит, що не вдався (і будь-які OPTIONS-запити перед ним), і подивіться на код статусу та заголовки відповіді.

Спершу перевірте код статусу. Багато «помилок CORS» насправді є серверною помилкою під маскою. Якщо сервер падає або повертає 404, його відповідь часто не містить заголовків CORS, тож браузер показує CORS замість справжньої проблеми. Виправте 500 або 404, і помилка CORS може зникнути.

Крок 2: Вирішіть, чи взагалі варто викликати цей API з браузера

Перш ніж додавати заголовки, запитайте себе: чи має браузер взагалі звертатися до цього API напряму?

  • Стороннє API, якому потрібен секретний ключ (OpenAI, секретний ключ Stripe, більшість сервісів email), ніколи не слід викликати з браузера. Ключ побачить кожен відвідувач. Викликайте його з бекенду, і проблема CORS зникне, бо запити між серверами не підлягають CORS. Див. як зберігати ключі API в безпеці.
  • Стороннє API, яким ви не керуєте, що не надсилає заголовків CORS, не можна виправити з вашого боку. Викликайте його з бекенду.
  • Ваше власне API можна налаштувати правильно. Продовжуйте нижче.

Крок 3: Виправте на сервері

Сервер має додавати правильні заголовки до всіх своїх відповідей, включно з відповідями з помилками.

Для самого запиту надішліть:

  • Access-Control-Allow-Origin: https://myapp.com (точний origin вашого фронтенду, без кінцевого слеша)
  • Vary: Origin, якщо значення залежить від того, який origin звернувся

Для preflight-запиту OPTIONS відповідайте успішним статусом (200 або 204) і додайте:

  • Access-Control-Allow-Origin: https://myapp.com
  • Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE
  • Access-Control-Allow-Headers: Content-Type, Authorization (кожен власний заголовок, який ви надсилаєте)
  • За бажанням Access-Control-Max-Age: 600, щоб браузер кешував preflight-відповідь певний час

Більшість фреймворків мають пакет або налаштування для цього. В Express це пакет cors, у FastAPI — CORSMiddleware, в ASP.NET Core — AddCors, у Spring — @CrossOrigin або конфігурація CORS. Типове налаштування для Express:

import cors from "cors";

app.use(cors({
  origin: ["https://myapp.com", "http://localhost:5173"],
  credentials: true,
}));

Розміщуйте обробку CORS перед своїми маршрутами та автентифікацією, щоб preflight-запити (які не містять входу) не відхилялися з помилкою 401.

Працюючи з конструктором на основі ШІ, опишіть налаштування точно:

Фронтенд на https://myapp.com викликає API на https://api.myapp.com і отримує помилку «Response to preflight request doesn't pass access control check». Налаштуй CORS в API так, щоб дозволялися саме https://myapp.com і origin превью, дозволь методи GET, POST, PATCH, DELETE із заголовками Content-Type і Authorization, обробляй OPTIONS до автентифікації та додавай заголовки CORS також до відповідей з помилками.

Крок 4: Обробіть cookies і облікові дані

Якщо ваш фронтенд надсилає cookies (наприклад, сесію входу) на інший origin, обидві сторони мають узгодити налаштування:

  • Фронтенд встановлює credentials: "include" у fetch або withCredentials: true в axios.
  • Сервер надсилає Access-Control-Allow-Credentials: true.
  • Access-Control-Allow-Origin на сервері має бути точним origin, а не *.

Cookies між сайтами також потребують SameSite=None; Secure, а деякі браузери додатково обмежують сторонні cookies. Це ще одна причина віддати перевагу підходу з кроку 5.

Крок 5: Уникніть CORS, налаштувавши один origin

Часто найчистіше рішення — взагалі не робити міжсайтових запитів. Віддавайте API з того самого origin, що й сторінку, наприклад за адресою https://myapp.com/api/...:

  • У розробці більшість dev-серверів уміють проксіювати. Налаштування server.proxy у Vite може переспрямовувати /api на ваш бекенд на іншому порту, тож браузер взаємодіє лише з одним origin.
  • У продакшені спрямуйте /api на бекенд через правила rewrite або проксі вашого хостингу, або віддавайте фронтенд і API з одного сервера.

Тоді фронтенд викликає відносний шлях, наприклад fetch("/api/orders"). Немає міжсайтового запиту, немає preflight між різними origin і немає клопоту з cookies. Крім того, не потрібно жорстко прописувати домен API, який відрізняється між превью та продакшеном.

Змініть фронтенд так, щоб він викликав бекенд через відносні шляхи /api замість повної URL-адреси, і налаштуйте dev-проксі, щоб /api переспрямовувався на сервер API. Потім приберіть налаштування CORS, які більше не потрібні.

Чого не варто робити

  • mode: "no-cors" у fetch. Це нічого не обходить: ваш код отримає порожню, нечитабельну відповідь.
  • Розширення браузера, що вимикають CORS. Вони змінюють лише ваш браузер. Кожен відвідувач однаково побачить помилку.
  • Публічні «CORS-проксі» для справжніх застосунків. Вони можуть читати й змінювати все, що через них проходить, і самі часто перестають працювати.
  • Access-Control-Allow-Origin: * для API, що використовує входи. Це й так не працює з обліковими даними, і це неправильний вибір за замовчуванням для приватних даних.
  • Відбиття будь-якого заголовка Origin назад з дозволеними обліковими даними. Це дає будь-якому сайту робити запити від імені ваших користувачів, які ввійшли. Використовуйте список дозволених origin.

Типові причини в застосунках, створених з ШІ

СитуаціяВиправлення
Фронтенд викликає стороннє API з секретним ключемПеренесіть виклик на бекенд
Працює в превью, не працює на опублікованому доменіДодайте опубліковані origin і origin власного домену до списку дозволених або використовуйте відносні шляхи /api
Помилка лише на POST, PUT або DELETEPreflight не оброблено; додайте обробку OPTIONS і дозволені заголовки
Помилка з'явилася після додавання входуОблікові дані потребують точного origin і Allow-Credentials
«Помилка CORS», але у вкладці Network показано 500Спершу виправте помилку сервера
URL API жорстко прописано як localhostВикористовуйте відносні шляхи або налаштування для кожного середовища

CORS у Mythex

Коли в проєкті Mythex є і сайт, і сервер API, обидва працюють як сервіси в одному проєкті, і ви можете перемикатися між ними в превью. Якщо попросити агента, щоб фронтенд викликав бекенд через відносний шлях /api, який у розробці проксіюється, це усуває більшість проблем CORS. Якщо ж вам потрібні міжсайтові виклики, дайте агенту точний текст помилки з консолі та задіяні origin. Перевірте результат і в опублікованому застосунку, бо його адреса відрізняється від превью. Див. Multi-service apps і API backends у документації, а також наші посібники як налагоджувати застосунок, створений з ШІ і фронтенд чи бекенд.

Чекліст CORS

  • Прочитано повний текст помилки в консолі та код статусу невдалого запиту
  • Виключено приховану 404 або 500
  • API з секретними ключами викликаються з бекенду, а не з браузера
  • Сервер надсилає Access-Control-Allow-Origin з точними дозволеними origin
  • Preflight OPTIONS відповідає дозволеними методами та заголовками, до автентифікації
  • Заголовки CORS присутні також у відповідях з помилками
  • Облікові дані: точний origin, Allow-Credentials: true, правильні налаштування cookies
  • Охоплено превью, опублікований домен і власний домен, або використано відносні шляхи /api
  • Немає no-cors, публічних проксі чи обхідних шляхів із відбиттям будь-якого origin

Запитання

Що означає помилка CORS?

Ваша сторінка, завантажена з одного origin, намагалася прочитати відповідь з іншого origin, а відповідь того сервера не містила заголовків, які це дозволяють. Браузер блокує читання відповіді вашим кодом. Виправлення — на сервері або в тому, як маршрутизується запит, а не у фронтенд-коді.

Чи можна виправити помилку CORS з фронтенду?

Не належним чином. Такі налаштування, як mode: 'no-cors', лише приховують відповідь від вашого коду. Виправляється це тим, що сервер надсилає правильний заголовок Access-Control-Allow-Origin, або викликом API з власного бекенду чи проксі на тому самому origin.

Чи безпечний Access-Control-Allow-Origin: *?

Це нормально для публічних даних, які може читати будь-хто, наприклад для публічного API без входу. Його не можна використовувати з cookies чи іншими обліковими даними, а для приватних API слід вказувати точні дозволені origin.

Чому запит працює в Postman або curl, але не в браузері?

CORS застосовується лише браузерами. Такі інструменти, як Postman і curl, його не застосовують, тож запит може успішно пройти там і все одно бути заблокованим, коли його виконує JavaScript сторінки.

Що таке preflight-запит?

Для запитів, які не є простими, наприклад JSON POST або запит із заголовком Authorization, браузер спочатку надсилає OPTIONS-запит і питає сервер, які методи й заголовки дозволені. Якщо цей OPTIONS-запит не вдається або не має потрібних заголовків, основний запит не надсилається взагалі.

Mythex · Pricing · Створюйте що завгодно з ШІ · Шаблони сайтів і застосунків · Порівняння Mythex · Глосарій створення застосунків за допомогою ШІ · Безкоштовні інструменти для створення застосунків за допомогою ШІ · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)