Руководства

Как исправить ошибки CORS (и почему они возникают)

Ошибка CORS означает, что ваша веб-страница пыталась прочитать ответ от другого источника (другого домена, порта или протокола), а сервер этого источника не прислал заголовки, которые разрешают доступ. Браузер блокирует ответ, чтобы защитить пользователей. Исправляется это на сервере: нужно вернуть заголовок Access-Control-Allow-Origin для origin вашего сайта и обработать preflight-запросы OPTIONS. Либо можно обойти проблему, отправляя запрос через собственный бэкенд на том же 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 мог быть сохранён, даже если вы увидели ошибку.
  • Ограничение действует только в браузерах. curl, Postman и серверный код CORS не применяют. Поэтому «работает в 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 checkPreflight-запрос OPTIONS не прошёл проверку
...must not be the wildcard '*' when the request's credentials mode is 'include'Вы отправляете cookie, а сервер ответил *
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, большинство почтовых сервисов), никогда не должен вызываться из браузера. Ключ станет видимым каждому посетителю. Вызывайте такой API из бэкенда — и проблема 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.

С AI-конструктором опишите настройку точно:

Фронтенд на 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: Настройте cookie и учётные данные

Если ваш фронтенд отправляет на другой origin cookie (например, сессию входа), обе стороны должны быть согласованы:

  • Фронтенд ставит credentials: "include" в fetch или withCredentials: true в axios.
  • Сервер отправляет Access-Control-Allow-Credentials: true.
  • Access-Control-Allow-Origin на сервере должен быть точным origin, а не *.

Межсайтовым cookie также нужны SameSite=None; Secure, а некоторые браузеры дополнительно ограничивают сторонние cookie. Это ещё одна причина предпочесть подход из шага 5.

Шаг 5: Избегайте CORS с помощью настройки same-origin

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

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

Тогда фронтенд обращается к относительному пути вроде fetch("/api/orders"). Нет кросс-доменного запроса, нет preflight между origin и проблем с cookie. Также не нужно жёстко прописывать домен API, который различается между предпросмотром и продакшеном.

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

Чего не делать

  • mode: "no-cors" в fetch. Это ничего не обходит: ваш код получит пустой, нечитаемый ответ.
  • Расширения браузера, которые отключают CORS. Они меняют только ваш браузер. Каждый посетитель всё равно увидит ошибку.
  • Публичные «CORS-прокси» для реальных приложений. Они могут читать и менять всё, что через них проходит, и периодически перестают работать.
  • Access-Control-Allow-Origin: * для API с логинами. С учётными данными это всё равно не работает, и это неправильное значение по умолчанию для закрытых данных.
  • Отражение любого заголовка Origin обратно с разрешёнными учётными данными. Так любой сайт может делать запросы от имени залогиненных пользователей. Используйте список разрешённых origin.

Частые причины в приложениях, созданных с ИИ

СитуацияРешение
Фронтенд вызывает сторонний API с секретным ключомПеренесите вызов на бэкенд
Работает в предпросмотре, не работает на опубликованном доменеДобавьте опубликованный домен и свой домен в список разрешённых или используйте относительные пути /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, правильные настройки cookie
  • Учтены origin предпросмотра, опубликованного сайта и собственного домена, либо используются относительные пути /api
  • Нет обходных путей через no-cors, публичные прокси или отражение любого origin

Вопросы

Что означает ошибка CORS?

Ваша страница, загруженная с одного источника, попыталась прочитать ответ с другого, а сервер того источника не отправил заголовки, которые разрешают такой доступ. Браузер не даёт вашему коду прочитать ответ. Исправляется это на сервере или в маршрутизации запроса, а не во фронтенд-коде.

Можно ли исправить ошибку CORS на фронтенде?

Нормально — нельзя. Настройки вроде mode: 'no-cors' только скрывают ответ от вашего кода. Исправить можно, заставив сервер отправлять правильный заголовок Access-Control-Allow-Origin, либо вызывая API из собственного бэкенда или прокси на том же origin.

Безопасен ли Access-Control-Allow-Origin: *?

Для публичных данных, которые может читать любой, например для открытого API без входа, это нормально. Такой заголовок нельзя использовать с cookie и другими учётными данными, а для закрытых 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 简体中文 繁體中文(香港) 繁體中文(台灣)