Гайды

Ошибка CORS — что делать: 3 причины и как починить каждую

Иллюстрация: браузер держит ответ на КПП, а чинится это на стороне сервера

Самое обидное в ошибке CORS — ты часами правишь фронтенд, а виноват не он. И вот тебе сюрприз, который экономит этот вечер: CORS почти никогда не чинится на фронтенде. Сколько заголовков ни добавляй в свой fetch — ничего не изменится. Решение всегда на сервере или в прокси.

Давай по схеме: симптом → причина → как проверить → как починить. Начнём с самой частой.

Симптом

В консоли браузера красное:

Access to fetch at '...' from origin '...' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

Важно понять: это не значит, что сервер лёг. Запрос дошёл, ответ пришёл — но браузер посмотрел на него и решил не отдавать твоему коду, потому что сервер не разрешил твой origin (домен + порт). Это защита, а не баг.

Причина 1 (самая частая): сервер не шлёт разрешающий заголовок

В девяти случаях из десяти дело в этом. Твой API отвечает, но в ответе нет заголовка Access-Control-Allow-Origin, и браузер прячет результат.

Как проверить. Открой DevTools → вкладка Network → кликни на упавший запрос → раздел Response Headers. Нет строки Access-Control-Allow-Origin — диагноз подтверждён.

Как починить. Добавь заголовок на сервере — там, где живёт API. Если это твой Express:

res.setHeader("Access-Control-Allow-Origin", "https://твой-сайт.ru");

Или подключи готовый пакет cors. В Supabase Edge Functions — отдай CORS-заголовки в ответе руками. Указывай конкретный домен, а не *, когда шлёшь куки или авторизацию.

Причина 2: не обрабатывается preflight (запрос OPTIONS)

Если ты шлёшь не простой запрос (метод PUT/DELETE, заголовок Authorization, тело JSON), браузер сначала отправляет предварительный запрос методом OPTIONS — спрашивает «а так можно?». Если сервер на OPTIONS не отвечает как надо, основной запрос даже не уйдёт.

Как проверить. В Network ты увидишь запрос OPTIONS перед твоим основным — и он красный или без нужных заголовков.

Как починить. Научи сервер отвечать на OPTIONS: вернуть статус 204 и заголовки Access-Control-Allow-Methods (например GET, POST, PUT, DELETE) и Access-Control-Allow-Headers (например Content-Type, Authorization). Пакет cors или фреймворк обычно делают это сами — главное не выключить.

Причина 3: ты дёргаешь чужой API прямо из браузера

Берёшь сторонний сервис (погода, курсы, чья-то модель) и зовёшь его прямо из фронтенда. А он твой origin не разрешает — и не обязан. Это не твой сервер, заголовки там не поправишь.

Как проверить. Запрос идёт на чужой домен, а не на твой. Документация сервиса часто прямо пишет «вызывайте с бэкенда».

Как починить. Ходи к чужому API через свой бэкенд (прокси): фронтенд зовёт твой сервер → твой сервер зовёт чужой REST API → отдаёт ответ фронтенду. Браузер общается только с твоим доменом — CORS снят. Бонус: ключ от чужого сервиса теперь спрятан на сервере, а не торчит в браузере.

Можно ли убрать CORS на фронтенде?

Нет. CORS — это правило браузера, и заголовки в твоём fetch на него не влияют. Чинится только на стороне, которая отдаёт данные: твой сервер — добавь заголовок; чужой — проксируй через свой.

Почему в Postman работает, а в браузере — ошибка CORS?

Потому что Postman и curl не браузеры — они не применяют политику CORS. Так что «в Postman ок» подтверждает: сервер жив и отвечает, проблема именно в разрешении для браузера. Это твоя подсказка, а не повод расстраиваться.

Поможет ли поставить Access-Control-Allow-Origin: *?

Иногда да, но осторожно: * разрешает всем и не работает вместе с куками/авторизацией — браузер такой ответ отклонит. Для запросов с входом указывай конкретный домен.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →