Форма отправляет заявку, но вместо подтверждения показывает ошибку. Разработчик открывает адрес API отдельно и видит ответ. Менеджер спрашивает: если сервер работает, почему сайт не получает данные? У такого расхождения может быть конкретная причина: браузер не разрешает коду страницы прочитать ответ другого источника.
В Гуси-Лебеди мы предлагаем разбирать CORS на одном воспроизводимом действии. Ниже покажем, какие сведения нужны команде, как отличить предварительную проверку от основного запроса и что принять после исправления.
CORS означает Cross-Origin Resource Sharing, механизм обмена ресурсами между источниками. Источник включает схему, хост и порт. Например, https://shop.example и https://api.example относятся к разным источникам; пути /catalog и /contacts на одном источнике сами по себе такого различия не создают. Сервер сообщает разрешения HTTP-заголовками, браузер применяет их к доступу скрипта к ответу. Общий принцип описан в руководстве MDN по CORS.
Это не проверка того, имеет ли пользователь право оформить заказ или увидеть чужой кабинет. CORS и серверную авторизацию нужно рассматривать отдельно. Исчезновение сообщения в консоли ещё не означает, что обмен работает правильно и права доступа настроены безопасно.
Как собрать сведения о заблокированном запросе

Начните с действия посетителя: открыть список товаров, отправить форму, войти в кабинет. Запишите адрес страницы и адрес API. Отметьте, возникает ли проблема до входа или только после него. Так разработчик получит сценарий, который можно повторить, а не общее сообщение «всё сломалось».
В инструментах разработчика откройте Network и Console. Повторите действие и найдите соответствующий запрос. Сохраните метод, статус, заголовки и текст ошибки. Если перед запросом есть OPTIONS, не пропускайте эту запись. Если нужных данных не видно, укажите это в задаче. Пароли, токены и персональные сведения перед передачей отчёта следует скрыть.
Браузер может не предоставить подробности ошибки самому JavaScript. Поэтому сообщение приложения вроде Failed to fetch нужно сопоставлять с консолью и сетевой записью, а не считать готовым диагнозом. Справка MDN об ошибках CORS также поясняет: отказ иногда намеренный, если сервис не разрешает обмен с этой страницей.
Представим перенос формы с тестового адреса на рабочий. Если API разрешал тестовый источник, а рабочий не добавили, команда должна проверить список разрешений. Это пример возможной причины, а не утверждение о вашем проекте. Аналогично нужно исследовать перенаправления и реальный ответ: ошибку приложения нельзя исправить случайной подстановкой заголовка.
Важное различие: отказ прочитать ответ не всегда означает, что запрос не дошёл до сервера. Не отправляйте платёж или заявку повторно только по строке CORS в консоли. Сначала выясните, выполнилась ли операция на стороне сервиса. При разборе запросов и ответов REST API этот вопрос связывают с контрактом конкретной операции.
Как проверять предварительный запрос и основной ответ

Некоторые обращения браузер предваряет проверкой preflight: отправляет OPTIONS и сообщает будущий метод и заголовки. Затем по ответу решает, можно ли отправить основной запрос. Не каждый междоменный обмен требует preflight, поэтому отсутствие OPTIONS само по себе не является неисправностью.
Например, отправка JSON с Content-Type: application/json обычно требует такой проверки. Если в Network виден OPTIONS, а основного запроса нет, разбирайте сначала предварительный ответ. При удачной проверке смотрите следующий шаг: разрешения должны соответствовать и фактическому обмену, а не только одному OPTIONS.
| Наблюдение | Что выяснить |
|---|---|
| OPTIONS получил отказ | Кто обрабатывает предварительный запрос и какие разрешения возвращает |
| Метод не разрешён | Совпадает ли ожидаемый метод с Access-Control-Allow-Methods |
| Заголовок не разрешён | Учтён ли нужный заголовок в Access-Control-Allow-Headers |
| Основной ответ не читается | Есть ли подходящий Access-Control-Allow-Origin в этом ответе |
Таблица помогает локализовать шаг, но не заменяет чтение точного сообщения. Один сервер может стоять за прокси, и правила следует искать в реальном маршруте обращения. Согласуйте, где формируются заголовки: в приложении, на веб-сервере или у посредника. Исправление в другом месте может не повлиять на ответ, который получает браузер.
Не меняйте метод или формат полезных данных только ради исчезновения preflight. Сначала проверьте, сохранится ли смысл операции и согласованный контракт API. Цель состоит в работающем обмене, а не в уменьшении числа записей Network.
Как согласовать источники и работу с учётными данными

Access-Control-Allow-Origin возвращает один источник. Для нескольких доверенных интерфейсов сервер сопоставляет Origin с разрешённым списком и возвращает подходящее значение. Список адресов через запятую или несколько одноимённых заголовков не является способом перечислить разрешения. Это правило и вопрос кеширования с Vary: Origin разобраны в документации заголовка Access-Control-Allow-Origin.
Звёздочка допускает чтение ресурса любым источником для запросов без учётных данных. Она может подходить публичному ресурсу, но не заменяет решение о доступе к личным данным. Для запроса с режимом credentials: include звёздочка в этом заголовке несовместима с разрешением доступа. Настройки клиента и ответа сервера необходимо рассматривать вместе.
Полезный рабочий документ содержит три вещи: адрес разрешённого интерфейса, назначение обмена и ответственного за правило. Разделите рабочую и тестовую среды. После появления нового поддомена или переноса интерфейса список следует пересмотреть, а не автоматически расширять до всех источников.
Почему no-cors не лечит получение JSON. Этот режим возвращает непрозрачный для JavaScript ответ: прочитать его тело и заголовки нельзя. Ограничения описаны в документации режима Request. Если интерфейсу нужны цены, список заказов или подтверждение заявки из ответа, такая замена не решает задачу.
Расширение браузера, которое скрывает ограничение на компьютере разработчика, также не подтверждает исправление для посетителей. Когда внешний API не поддерживает нужный обмен, обсудите с владельцем сервиса допустимую архитектуру. Собственный серверный посредник может стать частью решения, но его доступ, ошибки и сопровождение тоже требуют проектирования. Передавать пользовательские данные случайному публичному прокси не следует.
Как принимать исправление CORS

Приёмку начните с исходного действия в обычном браузере. Если речь о форме, проверьте не только сообщение «отправлено», но и предусмотренное получение заявки. Если интерфейс загружает данные, убедитесь, что он показывает ожидаемый результат и понятную ошибку при отказе сервиса.
Разберите отдельно разрешённый источник, источник вне согласованного списка и нужные состояния входа. Для каждого заранее запишите ожидаемый результат. Доступ пользователя к данным проверяется на сервере независимо от того, сможет ли браузер страницы прочитать ответ.
Для команды удобно зафиксировать результат коротко:
- Какое действие раньше не завершалось и где его повторили.
- Какие настройки изменены и кем согласованы.
- Что показали предварительный и основной запросы, если оба присутствуют.
- Как проверены получение результата и сценарий отказа.
- Какие среды или случаи ещё не проверены.
При доработке backend и правил доступа такая запись помогает вернуться к настройке после следующего выпуска. Для интерфейса полезно отдельно проверить поведение фронтенда при ошибке: посетитель должен понимать, завершилось ли действие и что можно сделать дальше.
Мы в Гуси-Лебеди считаем исправление понятным, когда команда может объяснить разрешённый обмен и повторить его проверку. Тогда CORS перестаёт быть загадочной строкой консоли и становится конкретной частью работы сайта с API.
