CORS в React и Axios: Полное руководство по исправлению ошибок безопасности браузера

CORS в React и Axios: Полное руководство по исправлению ошибок безопасности браузера

Вы разрабатываете крутое React-приложение, подключаетесь к API через axios, и вдруг — красная ошибка в консоли: "CORS policy blocked". Знакомо? Эта ошибка безопасности браузера останавливает многих разработчиков, но на самом деле её решение — это не магия, а понимание механизмов безопасности современного веба. В этой статье мы разберём CORS от А до Я и покажем все рабочие способы исправить проблему в вашем проекте.

Что такое CORS и почему браузер блокирует запросы?

CORS (Cross-Origin Resource Sharing) — это механизм безопасности браузера, который ограничивает кросс-доменные HTTP-запросы. Когда ваш React-приложение на localhost:3000 пытается получить данные с api.example.com, браузер отправляет предварительный запрос (preflight) с методом OPTIONS, чтобы проверить, разрешён ли доступ.

CORS работает только в браузерах! Если вы делаете запрос через Postman, cURL или Node.js-сервер — ошибки не будет. Это исключительно браузерная защита.

Типичная ошибка в React + Axios

Вот как выглядит стандартный код, вызывающий проблему:

import axios from 'axios';

const fetchData = async () => {
  try {
    const response = await axios.get('https://api.other-domain.com/data');
    console.log(response.data);
  } catch (error) {
    console.error('CORS Error:', error);
  }
};

И соответствующая ошибка в консоли: "Access to XMLHttpRequest at 'https://api.other-domain.com/data' from origin 'http://localhost:3000' has been blocked by CORS policy".

5 рабочих способов исправить CORS ошибку

1. Настройка сервера (правильный способ)

Идеальное решение — добавить правильные CORS-заголовки на стороне сервера:

  • Access-Control-Allow-Origin: Укажите ваш домен или '*' для всех доменов
  • Access-Control-Allow-Methods: Разрешите методы (GET, POST, PUT и т.д.)
  • Access-Control-Allow-Headers: Разрешите необходимые заголовки

Пример для Node.js + Express:

const cors = require('cors');
app.use(cors({
  origin: 'http://localhost:3000',
  methods: ['GET', 'POST'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

2. Прокси-сервер в development-режиме

Create React App позволяет настроить прокси в package.json:

{
  "proxy": "https://api.other-domain.com"
}

Или создайте файл setupProxy.js:

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'https://api.other-domain.com',
      changeOrigin: true,
      pathRewrite: {'^/api': ''},
    })
  );
};

3. Использование CORS-прокси сервисов

Для публичных API, которые вы не контролируете:

  1. cors-anywhere.herokuapp.com (для разработки)
  2. allorigins.win
  3. Собственный прокси на Vercel/Netlify
axios.get('https://cors-anywhere.herokuapp.com/https://api.target.com/data');

Публичные CORS-прокси не подходят для продакшена! Они могут быть медленными, ненадёжными и небезопасными для приватных данных.

4. Отключение CORS в браузере (только для разработки!)

Временное решение для локальной разработки:

  • Chrome: Запуск с флагом --disable-web-security
  • Использование расширения CORS Unblock
  • Приложение CORS Everywhere для Firefox

5. JSONP как альтернатива для GET-запросов

Старый, но рабочий метод для публичных API:

const script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=handleData';
document.body.appendChild(script);

window.handleData = (data) => {
  console.log('Received:', data);
};

Продвинутые сценарии с Axios

Настройка экземпляра Axios с CORS

const api = axios.create({
  baseURL: 'https://api.example.com',
  withCredentials: true, // Для отправки cookies
  headers: {
    'Content-Type': 'application/json',
  }
});

// Добавление интерцепторов для CORS
api.interceptors.request.use(config => {
  config.headers['X-Requested-With'] = 'XMLHttpRequest';
  return config;
});

Обработка preflight-запросов

Для сложных запросов (с кастомными заголовками или Content-Type) браузер отправляет OPTIONS-запрос. Убедитесь, что ваш сервер правильно на него отвечает:

// Серверная обработка OPTIONS
app.options('/data', (req, res) => {
  res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.sendStatus(200);
});

Лучшие практики и безопасность

  • Никогда не используйте Access-Control-Allow-Origin: * в продакшене с приватными данными
  • Всегда валидируйте Origin на сервере
  • Используйте environment variables для доменов
  • Для production используйте белый список разрешённых доменов
  • Регулярно обновляйте CORS-политики

FAQ: Частые вопросы о CORS

Почему CORS ошибка возникает только в браузере?

CORS — это механизм безопасности браузеров. Серверные приложения (Node.js, Python) и инструменты типа Postman не имеют таких ограничений.

Как отличить CORS ошибку от других?

CORS ошибка всегда содержит фразы "CORS policy", "Access-Control-Allow-Origin" или "cross-origin" в сообщении. Код статуса может быть 200, но браузер блокирует ответ.

Работает ли CORS с куками?

Да, но нужно установить withCredentials: true в Axios и Access-Control-Allow-Credentials: true на сервере. При этом Access-Control-Allow-Origin не может быть '*'.

Что делать если я не контролирую сервер API?

Используйте backend-прокси на вашем сервере или сервисы типа Cloudflare Workers для создания CORS-прослойки.

Как настроить CORS для нескольких доменов?

На сервере проверяйте Origin заголовок и динамически устанавливайте Access-Control-Allow-Origin для разрешённых доменов.

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

Теперь вы вооружены всеми необходимыми знаниями для борьбы с CORS ошибками в React-приложениях. Начните с правильной настройки сервера, используйте прокси для разработки и никогда не отключайте CORS в production. Удачного кодинга!