Понимание CORS: Почему ваш запрос не прошёл
Когда ваше JavaScript-приложение выбрасывает ошибку CORS, это не означает сломанный код — это браузер защищает пользователей от потенциальных угроз безопасности. Понимание причин возникновения этих ошибок требует понимания фундаментальной модели безопасности, которая управляет тем, как браузеры обрабатывают кросс-доменные запросы.
Ключевые моменты
- Ошибки CORS возникают, когда браузеры блокируют кросс-доменные запросы, не имеющие надлежащих разрешений со стороны сервера
- Политика одного источника (Same-Origin Policy) защищает пользователей, ограничивая запросы между различными источниками
- Простые запросы выполняются напрямую, в то время как сложные запросы требуют предварительной проверки через OPTIONS-запрос
- Отладка CORS требует изучения вкладки Network в браузере и проверки заголовков ответа сервера
Основа: Политика одного источника
Браузеры применяют Политику одного источника (Same-Origin Policy) в качестве основного механизма безопасности. Источник (origin) состоит из трёх частей: протокол (https://), домен (example.com) и порт (:3000). Когда они полностью совпадают, запросы проходят свободно. Когда они различаются — даже незначительно — вы делаете кросс-доменный запрос.
Рассмотрим эти источники:
https://app.example.com→https://api.example.com(разные поддомены = разные источники)http://localhost:3000→http://localhost:3001(разные порты = разные источники)http://example.com→https://example.com(разные протоколы = разные источники)
Без этой политики любой веб-сайт мог бы читать вашу почту Gmail, получать доступ к банковским данным или делать запросы от вашего имени. Совместное использование ресурсов между разными источниками (Cross-Origin Resource Sharing, CORS) обеспечивает контролируемое ослабление этих ограничений.
Как браузеры применяют CORS
Браузер выступает в роли контролёра, а не сервер. Это различие важно, потому что объясняет распространённые заблуждения:
- «Это работает в Postman/curl» — Эти инструменты не являются браузерами; они не применяют CORS
- «Добавление режима
no-corsисправит это» — Это не отключает CORS; это создаёт непрозрачный ответ, который вы не можете прочитать - «Сервер блокирует мой запрос» — Сервер отвечает нормально; браузер блокирует доступ к ответу
Когда вы делаете кросс-доменный запрос, браузер автоматически добавляет заголовок 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(как долго кэшировать это разрешение)
Discover how at OpenReplay.com.
Распространённые точки сбоя 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:
- Проверьте вкладку Network в браузере — Найдите предварительный
OPTIONS-запрос и изучите заголовки как запроса, так и ответа - Проверьте точное сообщение об ошибке — «CORS header ‘Access-Control-Allow-Origin’ missing» и «CORS header ‘Access-Control-Allow-Origin’ does not match» указывают на разные проблемы
- Сначала протестируйте без учётных данных — Удалите
credentials: 'include', чтобы изолировать проблемы, связанные с учётными данными - Подтвердите соответствие источников — Убедитесь, что протокол, домен и порт полностью совпадают
Заключение
Ошибки 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.