Ошибка 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: *?
Иногда да, но осторожно: * разрешает всем и не работает вместе с куками/авторизацией — браузер такой ответ отклонит. Для запросов с входом указывай конкретный домен.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





