← Назад к вопросам

Когда появляется ошибка Request blocked by CORS policy?

2.0 Middle🔥 211 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Когда возникает ошибка "Request blocked by CORS policy"?

Эта ошибка возникает в современных браузерах, когда веб-приложение, работающее в одном источнике (origin), пытается выполнить запрос к ресурсу, размещенному на другом источнике, и сервер этого ресурса не предоставляет правильных заголовков CORS (Cross-Origin Resource Sharing), явно разрешающих такой кросс-доменный запрос. Это механизм безопасности браузеров, предназначенный для предотвращения атак, таких как межсайтовая подделка запроса (CSRF) и утечка конфиденциальных данных.

Ключевые условия возникновения ошибки

Ошибка имеет следующий типичный вид в консоли браузера:

Access to fetch at 'https://api.example.com/data' from origin 'https://myapp.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Она появляется при одновременном соблюдении трех условий:

  1. Запрос выполняется из браузера (например, через fetch(), XMLHttpRequest, или AJAX-вызовы из библиотек). CORS — это политика, применяемая именно браузерами. Запросы с сервера (Node.js, Python) или через инструменты вроде curl или Postman не сталкиваются с этой блокировкой.
  2. Запрос является кросс-доменным (cross-origin). Происхождение (origin) определяется схемой (http://, https://), доменом (example.com, api.example.com) и портом (:3000, :8080). Любое несовпадение делает запрос кросс-доменным.
    *   **Пример:** Приложение на `http://localhost:3000` запрашивает данные с `http://localhost:8080` — **это разные origin (разные порты)**, и будет применена политика CORS.
  1. Сервер не отправляет корректные заголовки CORS в ответ на данный запрос. Браузер ожидает увидеть в ответе от сервера заголовки, начинающиеся с Access-Control-Allow-*.

Типы запросов и поведение CORS

Поведение браузера сильно зависит от типа выполняемого запроса:

1. Простые запросы (Simple Requests)

Это GET, HEAD, POST запросы с определенными (безопасными) заголовками (например, Accept, Accept-Language, Content-Language) и типами контента (application/x-www-form-urlencoded, multipart/form-data, text/plain). Для них браузер:

  • Немедленно отправляет запрос на сервер.
  • Если в ответе нет заголовка Access-Control-Allow-Origin, содержащего точный источник запроса или символ *, браузер блокирует ответ и выбрасывает ошибку CORS.

2. Непростые запросы (Preflighted Requests)

Запросы, не соответствующие критериям "простых" (например, с пользовательскими заголовками X-API-Key, с типом контента application/json или методы PUT, DELETE), требуют предварительного запроса (preflight).

  • Браузер сначала автоматически отправляет OPTIONS-запрос на целевой URL.
  • Этот запрос "спрашивает" у сервера: "Разрешены ли такие-то метод и заголовки с моего источника?".
  • Сервер должен ответить на этот OPTIONS-запрос заголовками:
    HTTP/1.1 204 No Content
    Access-Control-Allow-Origin: https://myapp.com
    Access-Control-Allow-Methods: GET, POST, PUT
    Access-Control-Allow-Headers: X-API-Key, Content-Type
    
  • Если ответ на preflight не содержит нужных разрешений, основной запрос даже не будет отправлен, и в консоли появится ошибка CORS, связанная с preflight.

Практические примеры сценариев

  • Разработка на локальном хосте: Фронтенд на http://localhost:3000 пытается получить данные с бэкенд-API на http://localhost:5000.
  • Разделение доменов: Продакшн-фронтенд на https://myshop.com обращается к платежному шлюзу на https://api.payment.com.
  • Использование внешних API: Приложение на вашем домене делает AJAX-запрос к публичному API, такому как https://api.weather.com, который может быть сконфигурирован для разрешения запросов только с определенных источников.
  • Запросы с пользовательскими заголовками: Даже к тому же домену добавление заголовка Authorization: Bearer ... может превратить запрос в "непростой" и потребовать preflight.

Решения и обходные пути (со стороны клиента и сервера)

Единственное правильное решение — корректно настроить сервер, чтобы он включал необходимые заголовки CORS в ответы. Например, в Node.js с Express:

const express = require('express');
const app = express();

// Middleware для обработки CORS
app.use((req, res, next) => {
  // Разрешаем запросы с конкретного origin
  res.header('Access-Control-Allow-Origin', 'https://myapp.com');
  // Или для всех (небезопасно для продакшна с данными!)
  // res.header('Access-Control-Allow-Origin', '*');

  // Разрешаемые методы
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');

  // Разрешаемые заголовки в запросе
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');

  // Обработка preflight-запроса
  if (req.method === 'OPTIONS') {
    return res.sendStatus(200);
  }
  next();
});

app.get('/api/data', (req, res) => {
  res.json({ message: 'Данные с CORS-заголовками!' });
});

app.listen(5000);

На стороне клиента обходные пути (не всегда применимы и часто являются плохой практикой):

  • Прокси-сервер в режиме разработки: Инструменты вроде webpack-dev-server (proxy setting) или create-react-app (proxy в package.json) направляют запросы через ваш dev-сервер, устраняя кросс-доменность.
  • Отключение CORS в браузере (ТОЛЬКО для разработки): Запуск браузера с флагами, отключающими безопасность (--disable-web-security), что категорически нельзя использовать для обычного серфинга.
  • Использование режима no-cors в fetch: Это позволяет отправить запрос, но делает ответ "непрозрачным" (opaque) — вы не сможете прочитать его тело или статус, что подходит только для очень специфичных сценариев (например, отправки аналитики).

Итог

Ошибка "Request blocked by CORS policy" — это не ошибка вашего кода или сервера в классическом понимании, а стратегический отказ браузера выполнить потенциально небезопасный кросс-доменный запрос. Она служит защитой пользователя. Для её устранения необходимо обеспечить, чтобы сервер, на который направлен запрос, предоставлял клиентскому приложению явные и корректные права доступа через заголовки HTTP-ответа Access-Control-Allow-*.