РуководстваОпубликовано: 04.10.2026• 0 просмотров

AI API работает через curl, но браузер сообщает CORS: проверка preflight и доступа

Проверка OPTIONS, Origin и заголовков ответа: как отличить отказ preflight от ошибки API и организовать серверные вызовы без раскрытия ключа.

AI API работает через curl, но браузер сообщает CORS: проверка preflight и доступа

Адрес API и модель работают в командной строке, но на сайте появляются blocked by CORS policy или TypeError: Failed to fetch. Это не обязательно означает, что ключ недействителен или нужно пополнить баланс. Браузер дополнительно проверяет разрешение на чтение ответа другого источника, тогда как curl не блокирует ответы по правилам браузерного CORS.

Руководство помогает отличить сетевую ошибку, отказ предварительной проверки и недоступный для JavaScript ответ. Это описание общего поведения HTTP, а не результаты тестирования конкретного посредника. Не каждый провайдер разрешает прямые вызовы из браузера.

1. Убедитесь, что проблема действительно в CORS

Источник, или origin, определяется протоколом, именем хоста и портом. У https://app.example.com и https://api.example.com разные источники. HTTP и HTTPS на одном домене также различаются, как и http://localhost:3000 и http://localhost:3001.

При обращении к другому источнику браузер проверяет, разрешает ли сервер текущему сайту читать ответ. CORS не заменяет проверку API-ключа. Успешный вызов из командной строки не доказывает, что такой же вызов разрешён веб-странице.

Откройте Console и Network в инструментах разработчика, повторите короткий запрос и выберите направление проверки:

Что видноЧто проверять
Сообщение CORS и запрос OPTIONSСтатус preflight, разрешённые источники, методы и заголовки
OPTIONS успешен, но POST блокируетсяCORS-заголовки фактического ответа, включая ответы с ошибкой
POST возвращает доступный JSON с 401/403Ключ и права доступа, а не сам механизм CORS
Только Failed to fetch без указания CORSDNS, TLS, обрыв соединения, CSP и блокировки браузера
HTTPS-страница обращается к HTTP APIОграничения смешанного содержимого; CORS-заголовки их не устранят

Данные Network иногда неполны. Сопоставляйте их с Console и серверными журналами, не объясняя любую сетевую ошибку одним лишь CORS.

2. OPTIONS — предварительная проверка, а не повторная генерация

Межсайтовый запрос с Authorization или POST с Content-Type: application/json обычно вызывает preflight. Браузер отправляет OPTIONS, чтобы узнать, разрешены ли текущему источнику метод POST и нужные заголовки.

В таком запросе используются Origin, Access-Control-Request-Method и Access-Control-Request-Headers. Он не просит модель сгенерировать ответ. При корректной реализации OPTIONS не должен запускать инференс или тарифицироваться как генерация; включается ли он в общую статистику запросов провайдера, нужно уточнять отдельно.

Если preflight не проходит, браузер обычно не отправляет основной запрос. Возможные причины: шлюз не принимает OPTIONS, перенаправляет его на страницу входа, требует от него API-ключ или разрешает другой origin.

Предварительная проверка не должна требовать Bearer-ключ основного вызова. Разрешить контролируемый preflight — не значит отключить авторизацию POST: эти этапы нужно обрабатывать раздельно.

3. Проверьте preflight без секретов

В команде ниже используются условные домены. Замените первый адрес на полный endpoint из документации, а Origin — на источник вашего сайта, без пути и завершающего слеша. Проверяйте только интерфейсы, которыми вы вправе пользоваться.

curl -i -X OPTIONS "https://api.example.com/v1/chat/completions" -H "Origin: https://app.example.com" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: authorization,content-type"

В Windows PowerShell можно заменить начальное curl на curl.exe. Команда не содержит API Key и не отправляет пользовательский prompt.

Один из возможных разрешающих ответов для этого примера:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: authorization, content-type
Vary: Origin

Успешный статус не обязан быть именно 204. Важнее совпадение разрешённого источника, метода и заголовков с реальным запросом. Authorization следует перечислять явно: не рассчитывайте, что любой символ * автоматически разрешит этот заголовок.

Если сервер выбирает разрешённый origin динамически, используйте проверенный список источников и Vary: Origin, чтобы кэш не отдавал заголовки одного источника другому. Не отражайте произвольный Origin без проверки.

При credentials: 'include' нужен также Access-Control-Allow-Credentials: true, а разрешённый источник не может быть *. Отправка Cookie дополнительно зависит от SameSite и политики сторонних Cookie браузера. Не включайте credentials без необходимости только ради устранения ошибки.

curl показывает ответ сервера, но не выполняет браузерную проверку CORS. Поэтому команда не заменяет проверку в настоящем браузере. Кроме успешного OPTIONS, нужные заголовки должны присутствовать и в фактическом ответе POST. Ответы 401, 429 и 5xx должны следовать той же политике источников, иначе веб-приложение увидит CORS вместо исходной ошибки.

4. Для сайта храните ключ провайдера на сервере

Если ваш сайт оплачивает обращения к AI от своего имени, обычная схема выглядит так:

Браузер пользователя → сервер вашего сайта → API провайдера

Браузер обращается к вашему endpoint, а ключ остаётся в серверных переменных окружения или хранилище секретов. Серверный запрос к провайдеру не ограничен браузерным CORS, но по-прежнему зависит от сети, TLS, авторизации, квот и тайм-аутов. Если браузер и ваш сервер находятся на разных источниках, CORS нужно настроить и между ними.

Для собственного серверного интерфейса как минимум нужны:

  1. Проверка личности и прав пользователя; при сессиях на Cookie — также защита от CSRF.
  2. Фиксированный адрес провайдера или список разрешённых адресов и моделей, без произвольного URL от пользователя.
  3. Лимиты частоты, параллелизма, расходов и размера запроса на пользователя.
  4. Ограничения времени и вывода, без бесконечных повторов.
  5. Фильтрация логов, чтобы в них не попадали ключи, полные страницы ошибок и чувствительные диалоги.

Иначе вместо открытого ключа вы получите открытый серверный интерфейс, через который любой сможет расходовать ваш баланс. CORS не заменяет защиту сервера: другие программы не обязаны соблюдать браузерные правила. Подробнее о хранении ключей — в руководстве по безопасности API Key.

5. Что не решает проблему

  • mode: 'no-cors': межсайтовый ответ становится opaque, его тело и заголовки недоступны JavaScript; методы и заголовки запроса также ограничены. Для чтения обычного JSON-ответа чата это не подходит.
  • Access-Control-Allow-Origin в запросе браузера: это заголовок ответа сервера. Одноимённый заголовок запроса не предоставляет доступ и может вызвать дополнительную проверку.
  • Ключ в исходниках страницы: сборка, минификация и обфускация не делают отправленный в браузер ключ секретным.
  • Отключение защиты браузера или расширение для обхода CORS: это не исправление сайта для обычных пользователей.
  • Немедленный повтор после сообщения CORS: POST мог уже дойти до сервера, выполнить генерацию и вызвать списание, даже если браузер не смог прочитать ответ.

Сначала проверьте в Network, был ли только OPTIONS или отправился и POST, затем сопоставьте это с журналом вызовов провайдера. Так можно избежать повторных запросов без необходимости.

6. Как проверить исправление

Используйте тестовый аккаунт и короткий запрос. Проверьте работу разрешённого источника, возможность чтения ответа с неразрешённого источника и видимость ошибок. Блокировка чтения браузером не доказывает, что сервер не выполнил операцию: отдельно проверяйте серверную авторизацию.

Перед запуском убедитесь, что ключ провайдера отсутствует в файлах сайта и запросах браузера, сервер ограничивает адреса пересылки, проверены и OPTIONS, и основной ответ, а 401/429/5xx дают понятные сообщения. В логах не должно быть секретов. Для остальных сбоев используйте порядок диагностики ошибок API.

Поддержке передайте время, Origin сайта, домен и путь API, статусы OPTIONS/POST и обезличенные заголовки ответа. Не публикуйте экспортированный HAR без очистки: он может содержать Authorization, Cookie, параметры URL и тело запроса.

Источники, просмотренные 30.09.2026: MDN: CORS, MDN: Preflight request, MDN: Request.mode. Путь API, авторизация и политика разрешённых источников определяются актуальной документацией провайдера.

Опубликовано: 4 октября 2026 г.

Похожие статьи

Отказ от ответственности

Данные о сервисах и ценах вводятся вручную; доступность сайтов проверяется автоматически с указанием времени последней проверки.Информация о провайдерах может меняться, поэтому перед оплатой рекомендуем посетить официальный сайт сервиса. Мы не гарантируем качество услуг сторонних провайдеров.

© 2026 Выбор API. All rights reserved.