Back

Понимание CORS: Почему ваш запрос не прошёл

Понимание CORS: Почему ваш запрос не прошёл

Когда ваше JavaScript-приложение выбрасывает ошибку CORS, это не означает сломанный код — это браузер защищает пользователей от потенциальных угроз безопасности. Понимание причин возникновения этих ошибок требует понимания фундаментальной модели безопасности, которая управляет тем, как браузеры обрабатывают кросс-доменные запросы.

Ключевые моменты

  • Ошибки CORS возникают, когда браузеры блокируют кросс-доменные запросы, не имеющие надлежащих разрешений со стороны сервера
  • Политика одного источника (Same-Origin Policy) защищает пользователей, ограничивая запросы между различными источниками
  • Простые запросы выполняются напрямую, в то время как сложные запросы требуют предварительной проверки через OPTIONS-запрос
  • Отладка CORS требует изучения вкладки Network в браузере и проверки заголовков ответа сервера

Основа: Политика одного источника

Браузеры применяют Политику одного источника (Same-Origin Policy) в качестве основного механизма безопасности. Источник (origin) состоит из трёх частей: протокол (https://), домен (example.com) и порт (:3000). Когда они полностью совпадают, запросы проходят свободно. Когда они различаются — даже незначительно — вы делаете кросс-доменный запрос.

Рассмотрим эти источники:

  • https://app.example.comhttps://api.example.com (разные поддомены = разные источники)
  • http://localhost:3000http://localhost:3001 (разные порты = разные источники)
  • http://example.comhttps://example.com (разные протоколы = разные источники)

Без этой политики любой веб-сайт мог бы читать вашу почту Gmail, получать доступ к банковским данным или делать запросы от вашего имени. Совместное использование ресурсов между разными источниками (Cross-Origin Resource Sharing, CORS) обеспечивает контролируемое ослабление этих ограничений.

Как браузеры применяют CORS

Браузер выступает в роли контролёра, а не сервер. Это различие важно, потому что объясняет распространённые заблуждения:

  1. «Это работает в Postman/curl» — Эти инструменты не являются браузерами; они не применяют CORS
  2. «Добавление режима no-cors исправит это» — Это не отключает CORS; это создаёт непрозрачный ответ, который вы не можете прочитать
  3. «Сервер блокирует мой запрос» — Сервер отвечает нормально; браузер блокирует доступ к ответу

Когда вы делаете кросс-доменный запрос, браузер автоматически добавляет заголовок Origin. Сервер должен ответить заголовком Access-Control-Allow-Origin, который соответствует вашему источнику (или * для публичных ресурсов). Отсутствие соответствующего заголовка означает, что браузер блокирует доступ к ответу — отсюда и ваша ошибка CORS.

Простые запросы против предварительных запросов

Не все запросы вызывают одинаковое поведение CORS. Простые запросы проходят немедленно, в то время как другие требуют предварительного запроса (preflight).

Простые запросы (без предварительной проверки)

Эти запросы соответствуют ВСЕМ следующим критериям:

  • Метод: GET, HEAD или POST
  • Заголовки: Только простые заголовки (Accept, Content-Language, Content-Type)
  • Content-Type: Только application/x-www-form-urlencoded, multipart/form-data или text/plain

Запросы, вызывающие предварительную проверку

Любой запрос, нарушающий критерии простого запроса, вызывает предварительный OPTIONS-запрос:

  • Методы типа PUT, DELETE, PATCH
  • Пользовательские заголовки (Authorization, X-API-Key)
  • Content-Type: application/json (да, JSON вызывает предварительную проверку)

Предварительный запрос запрашивает разрешение перед отправкой вашего фактического запроса. Сервер должен ответить соответствующими заголовками:

  • Access-Control-Allow-Methods (какие методы разрешены)
  • Access-Control-Allow-Headers (какие заголовки допустимы)
  • Access-Control-Max-Age (как долго кэшировать это разрешение)

Распространённые точки сбоя CORS

Отсутствующие или неправильные заголовки

Сервер не возвращает заголовок Access-Control-Allow-Origin, или он не соответствует вашему источнику. Помните: http://localhost:3000 и http://localhost:3001 — это разные источники.

Ограничения учётных данных

Включение учётных данных (credentials: 'include' или withCredentials: true) добавляет ограничения:

  • Сервер должен включить Access-Control-Allow-Credentials: true
  • Access-Control-Allow-Origin не может быть * — он должен указывать ваш точный источник
  • Cookies должны соответствовать требованиям SameSite

Сложности с редиректами

CORS и редиректы плохо взаимодействуют. Редирект на другой источник во время CORS-запроса часто терпит неудачу, потому что браузер некорректно обрабатывает смену источника. Избегайте кросс-доменных редиректов в CORS-запросах.

Доступ к частной сети

Современные браузеры добавляют дополнительную защиту, когда публичные веб-сайты обращаются к ресурсам частной сети (localhost, 192.168.x.x, 10.x.x.x). Эти запросы могут требовать дополнительных заголовков, таких как Access-Control-Allow-Private-Network, и вызывать предварительную проверку даже для простых запросов. Эта защита предотвращает сканирование вашей локальной сети внешними веб-сайтами.

Эффективная отладка CORS

При столкновении с ошибками CORS:

  1. Проверьте вкладку Network в браузере — Найдите предварительный OPTIONS-запрос и изучите заголовки как запроса, так и ответа
  2. Проверьте точное сообщение об ошибке — «CORS header ‘Access-Control-Allow-Origin’ missing» и «CORS header ‘Access-Control-Allow-Origin’ does not match» указывают на разные проблемы
  3. Сначала протестируйте без учётных данных — Удалите credentials: 'include', чтобы изолировать проблемы, связанные с учётными данными
  4. Подтвердите соответствие источников — Убедитесь, что протокол, домен и порт полностью совпадают

Заключение

Ошибки CORS — это не произвольные препятствия, это браузер, защищающий пользователей от вредоносных кросс-доменных запросов. Сервер объявляет, какие источники могут получить доступ к его ресурсам через заголовки CORS, а браузер применяет эти правила. Понимание этой модели превращает CORS из загадочного блокировщика в предсказуемую систему, которую вы можете методично отлаживать.

Когда ваш запрос не проходит, проверьте, является ли он простым или требует предварительной проверки, убедитесь, что заголовки CORS сервера точно соответствуют вашему источнику, и помните, что инструменты типа Postman полностью обходят эти проверки. Браузер выполняет свою работу — ваша задача состоит в том, чтобы сервер предоставлял правильные разрешения.

Часто задаваемые вопросы

Postman и другие инструменты тестирования API не применяют политики CORS. Только браузеры реализуют эти ограничения безопасности. Ваш сервер должен отправлять правильные заголовки Access-Control-Allow-Origin, чтобы запросы из браузера были успешными.

Хотя браузеры предлагают флаги для отключения функций безопасности, это рискованно и влияет на все сайты. Вместо этого настройте ваш сервер разработки на отправку соответствующих заголовков CORS или используйте прокси-сервер для обработки кросс-доменных запросов во время разработки.

Спецификация CORS считает простыми только три типа контента: application/x-www-form-urlencoded, multipart/form-data и text/plain. Любой другой тип контента, включая application/json, вызывает предварительный OPTIONS-запрос для проверки разрешений.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay