Gernar
Frontend DeveloperHTTP, API и сеть

Интервью-вопрос

Что такое CORS ошибка

CORS ошибка означает, что браузер заблокировал доступ frontend-кода к ответу с другого origin. В ответе важно показать, какие заголовки проверять, где чинить проблему и почему это не лечится одной настройкой fetch.

Добавлен
Редакция

Подготовьте короткий ответ и пару деталей на случай уточняющих вопросов.

🐰0
🥚0

Мини-квиз

Проверка перед разбором

Несколько быстрых вопросов перед разбором. Так проще поймать места, которые только кажутся понятными.

Вопрос 1 из 60 правильно

Как лучше коротко объяснить CORS ошибку?

Вы отвечаете на интервью и хотите сразу показать практический смысл ошибки.

Варианты ответа

Разбор

Разобраться, а не зазубрить

Дальше разбираем суть, типичные уточнения и места, где легко сказать лишнее или перепутать термины.

Базовая идея

CORS расшифровывается как Cross-Origin Resource Sharing. Это механизм браузера, который решает, может ли JavaScript на одной странице прочитать ответ, полученный с другого origin.

Важно сказать именно про доступ к ответу, а не только про отправку запроса. Для части запросов браузер может отправить запрос на сервер, получить ответ, а потом заблокировать доступ к нему в JavaScript, если сервер не дал разрешение. Для запросов с preflight браузер сначала делает OPTIONS и может не отправить основной запрос вообще.

Короткая формулировка для интервью:

CORS ошибка значит, что браузер не дал моему frontend-коду использовать ответ с другого origin. Сервер должен явно разрешить origin, метод, нужные заголовки и credentials через CORS заголовки. Если этого нет, проблему чинят на сервере или proxy, а не магическим флагом в React.

Что считается другим origin

Origin состоит из трех частей: схема, host и порт. Если отличается хотя бы одна часть, для браузера это другой origin.

https://app.example.com        -> origin: https + app.example.com + 443
https://api.example.com        -> другой host
http://app.example.com         -> другая схема
https://app.example.com:3000   -> другой порт

Поэтому frontend на http://localhost:3000 и API на http://localhost:8080 тоже находятся на разных origin. Из-за этого локально легко получить CORS ошибку, хотя оба сервиса запущены на одном компьютере.

Что происходит при запросе

Для простого запроса браузер может сразу обратиться к серверу. Если в ответе нет подходящего Access-Control-Allow-Origin, JavaScript не получит доступ к телу и заголовкам ответа.

Для более сложного запроса браузер сначала отправляет preflight:

fetch("https://api.example.com/profile", {
  method: "PATCH",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${token}`,
  },
  body: JSON.stringify({ name: "Alex" }),
});

Здесь preflight вероятен из-за PATCH, Content-Type: application/json и Authorization. Сервер должен ответить на OPTIONS так, чтобы браузер увидел разрешенные method и headers. Если gateway возвращает 404, 403 или редирект на login для OPTIONS, основной PATCH не уйдет.

Как искать причину

На интервью полезно описать не только определение, но и порядок диагностики. Так ваш ответ звучит как реальный опыт разработки.

Как искать причину CORS ошибки

1Ошибка есть в браузере, но запрос работает в curl или Postman?
Проверьте CORS заголовки ответа и preflight. Это браузерная политика.
2Запрос использует PATCH, DELETE, Authorization или application/json?
Откройте OPTIONS запрос. Сервер должен разрешить метод и нужные headers.
3Нужны cookies или сессия?
Используйте credentials: include на клиенте. На сервере нужен конкретный origin и Access-Control-Allow-Credentials.
4Вы не контролируете внешний API?
Используйте свой backend, BFF или proxy. Не пытайтесь обойти CORS из браузера.
5Пользователь видит пустой список или вечный loading?
Проверьте, не замаскирована ли CORS ошибка под empty state. Покажите ошибку загрузки, а техническую причину отправьте в лог.

Какие ответы сервера важны frontend-разработчику

Вам не нужно помнить все детали спецификации наизусть. Важно понимать, какие заголовки влияют на поведение браузера и какой баг они создают в UI.

Что проверить в Network

Нет разрешения originMissing ACAO

Браузер не даст прочитать ответ. Сервер должен вернуть Access-Control-Allow-Origin с вашим origin.

Preflight отклоненOPTIONS 403/404

Основной запрос не уйдет. Нужно разрешить OPTIONS, метод и заголовки вроде Authorization.

Cookies и wildcard* + credentials

Браузер отклонит ответ. Для cookies нужен конкретный origin и Access-Control-Allow-Credentials: true.

Dev proxylocal only

Подходит для разработки. В продакшене нужен реальный proxy, gateway или настройка API.

Неправильный режимno-cors

Запрос может стать opaque. Вы не прочитаете статус и тело, поэтому это не лечение CORS ошибки.

Что не стоит делать на клиенте

Неудачный вариант:

fetch("https://api.example.com/users", {
  headers: {
    "Access-Control-Allow-Origin": "*",
  },
});

Это не исправляет CORS. Access-Control-Allow-Origin это заголовок ответа сервера, а не просьба клиента. Браузер проверяет, что сервер разрешил доступ. Такой код может только добавить лишний header, спровоцировать preflight и сломать загрузку данных. Лучше убрать этот header из frontend-кода и настроить CORS на API, gateway, BFF или proxy.

Еще один неудачный вариант:

fetch("https://api.example.com/users", {
  mode: "no-cors",
});

Такой запрос не дает нормальный ответ для приложения. Часто вы получите opaque response без тела, нормального статуса и полезной обработки ошибок. Для UI это значит пустые данные, вечный loading, неправильную аналитику и сложную отладку. Лучше оставить обычный CORS-запрос, показать ошибку пользователю и исправить серверную настройку или добавить свой proxy.

Как выглядит нормальное исправление

Если вы контролируете сервер, он должен вернуть CORS заголовки под ваш сценарий. Конкретный код зависит от backend-стека, но идея такая:

app.use(cors({
  origin: "https://app.example.com",
  credentials: true,
  methods: ["GET", "POST", "PATCH", "DELETE"],
  allowedHeaders: ["Content-Type", "Authorization"],
}));

Этот пример не нужно копировать вслепую. В продакшене важно разрешать только доверенные origin, не открывать приватное API через * без причины и отдельно проверить preflight. Если включаете cookies, клиенту нужен credentials: "include", а серверу нужны корректные cookie-атрибуты и CSRF защита. Если API внешний и вы не можете менять его настройки, нормальный путь такой: свой backend, BFF или proxy. Он делает запрос сервер-сервер и отдает фронтенду данные с вашего origin.

Практический вывод для frontend

В сильном ответе вы показываете границу ответственности. Frontend может увидеть ошибку, проверить Network, понять preflight, настроить credentials и не добавлять лишние headers. Но разрешение на чтение ответа выдает сервер.

Еще важно не продавать CORS как защиту API. CORS не отменяет авторизацию, проверку прав и CSRF защиту. Если запрос меняет состояние и использует cookies, сервер должен сам проверять пользователя, CSRF token или другой признак намерения. Часть cross-origin запросов может дойти до сервера даже тогда, когда браузер потом не даст прочитать ответ.

Частые ошибки

Где обычно ошибаются

Проверьте формулировки, которые звучат уверенно, но на интервью быстро выдают пробелы.

  1. 1

    Пытаться выставить CORS заголовки в запросе

    Заголовки Access-Control-Allow-* должен вернуть сервер в ответе, а не frontend в запросе. Если добавить их в fetch, браузер не начнет доверять ответу. Лучше проверить response headers и договориться о настройке API или proxy.

  2. 2

    Считать CORS полноценной защитой API

    CORS ограничивает браузерный JavaScript, но не мешает прямым запросам с сервера, из curl или Postman. Авторизация, проверка прав, CSRF защита и валидация должны жить на сервере. Иначе API останется уязвимым, даже если в браузере видна CORS ошибка.

  3. 3

    Лечить ошибку через mode: no-cors

    mode: "no-cors" не дает нормальный JSON ответ. Часто вы получаете opaque response без доступа к статусу и телу. Это ломает обработку ошибок, аналитику и пользовательский сценарий.

  4. 4

    Забывать про OPTIONS

    При preflight падает не основной PATCH или POST, а предварительный OPTIONS. Если gateway требует авторизацию на OPTIONS или возвращает 404, браузер не отправит основной запрос. Проверяйте preflight отдельно в Network.

  5. 5

    Ставить wildcard для приватного API

    Access-Control-Allow-Origin: * может быть нормален для публичных ресурсов без credentials, но это плохая привычка для приватного API. С cookies он еще и не сработает. Безопаснее явно перечислить доверенные origin и не смешивать это с авторизацией.

  6. 6

    Маскировать CORS под пустые данные

    Если в catch вернуть пустой массив, пользователь увидит empty state вместо сбоя интеграции. Это ломает UX, аналитику и диагностику. Лучше показать состояние ошибки, дать повторить запрос и отправить техническую причину в лог.

Follow-up

Что могут спросить дальше

Короткие ответы на вопросы, которыми проверяют понимание CORS, preflight и настройки запросов из браузера.

Живые ответы

Видео с похожим вопросом

Если найдем публичные интервью с таким вопросом, добавим их сюда. Их удобно смотреть после теории, чтобы свериться с живыми ответами.

Пока видео нет. Когда появятся подходящие публичные интервью, добавим их в этот блок, чтобы можно было сравнить разбор с тем, как отвечают реальные кандидаты.

Содержание