#Что происходит и как распознать неисправность
Когда браузер отправляет межсайтовый запрос с нестандартными заголовками или определёнными методами, он может сначала выполнить OPTIONS для проверки разрешений CORS. Если ответ на этот запрос неправильный, основной POST/PUT не отправляется, а fetch сообщает об ошибке. Это отличается от таймаута и обычного HTTP 500.
#Как отличить причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Сервер не обрабатывает OPTIONSМаршрут API принимает POST, но на предварительный OPTIONS возвращает 404/405/401. | В «Сеть» видна ошибка именно OPTIONS. | Настройте обработку OPTIONS до проверки авторизации тела запроса. |
| Недопустимый Origin, метод или заголовокОтвет не содержит подходящих Access-Control-Allow-* заголовков. | Консоль сообщает конкретный отсутствующий заголовок. | Разрешите строго нужный origin/method/header на API. |
| Прокси или перенаправлениеOPTIONS попадает на другой сервер или перенаправляется на форму входа. | В сетевом ответе 301/302, HTML страницы входа или ошибка прокси. | Исправьте маршрутизацию на сервере/шлюзе. |
#Пошаговая диагностика и исправление
- Проверьте ошибку именно в браузереОткройте страницу с проблемой в Chrome/Edge или Firefox, нажмите F12, выберите вкладку «Сеть» (Network), включите сохранение журнала запросов при перезагрузке, затем повторите действие. Используйте фильтр по адресу API, найдите запрос с методом OPTIONS. Если OPTIONS вообще нет, а fetch всё равно падает, ищите сетевую/TLS-причину, а не меняйте CORS.
- Сверьте адрес, инициатор и источник OriginЩёлкните OPTIONS → «Заголовки» (Headers). Сравните Request URL, Origin, Access-Control-Request-Method, Access-Control-Request-Headers. Сохраните только домены без токенов и персональных параметров. Если запрос ушёл на тестовый адрес вместо рабочего, исправьте настройку URL клиента и повторите проверку.
- Посмотрите статус и ответ на OPTIONSВ той же карточке запроса найдите статус ответа. 404/405 означает, что маршрутизация не принимает OPTIONS; 401/403 может значить, что авторизация перехватывает предварительный запрос. Проверьте Response Headers:
Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Headers; если их нет, проблему решает владелец API, а не настройка fetch в браузере. - Разрешите конкретный источник на сервереЕсли вы администрируете API, создайте точное правило CORS для адреса страницы, например
https://app.example.org, и разрешите фактически используемые метод и заголовки. Настройте ответ на OPTIONS в серверном приложении или проверенном CORS-посреднике до запроса пользовательской авторизации. Для запросов с учётными данными нельзя использоватьAccess-Control-Allow-Origin: *; нужен явный origin и разрешённые credentials. - Проверьте, не мешает ли промежуточный серверЕсли на API есть обратный прокси, балансировщик или WAF, откройте его конфигурацию и журналы. Сверьте фактический путь и проверьте, не заменяет ли он ответ OPTIONS перенаправлением. Изменяйте настройки на тестовом сервере; перед перезагрузкой Nginx обязательно сохраните файл конфигурации и выполните
nginx -tс правами администратора. - Не обходите CORS небезопасными трюкамиНе добавляйте
mode: "no-cors"ради чтения ответа: такой режим даёт opaque response, который не решает получение JSON. Не отключайте политику безопасности браузера, расширения защиты или проверку сертификатов. Если у вас нет доступа к API, отправьте владельцу статус OPTIONS, Origin и ожидаемые заголовки. - Проверьте разрешение и фактический POSTПерезагрузите страницу, повторите действие с открытой вкладкой «Сеть». Ожидается успешный OPTIONS с нужными разрешениями и затем основной POST/PUT, который может вернуть собственный HTTP-код. При ошибке сравните запросы до и после, отмените тестовую CORS-настройку, если она открыла лишние источники.
#Команды и примеры для проверки
fetch("https://api.example.org/data", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({test: true})
}).then(r => console.log(r.status)).catch(console.error);#Как проверить результат и что делать дальше
Проверка успешна, когда браузер разрешает предварительный запрос и отправляет основной запрос. Ошибки основного API (401, 403, 500) исправляются отдельно; не путайте их с Failed to fetch до основного ответа.