Вы разрабатываете современное React-приложение, подключаетесь к API с помощью Axios, и внезапно в консоли браузера появляется зловещая ошибка: "Access to XMLHttpRequest at 'http://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policy". Это знакомая боль для фронтенд-разработчиков. CORS (Cross-Origin Resource Sharing) — это не баг, а механизм безопасности браузеров, но его настройка часто вызывает головную боль. В этой статье мы разберем CORS до мельчайших деталей и рассмотрим все практические способы решения проблемы — от быстрых хаков для разработки до правильных конфигураций для продакшена.
Что такое CORS и почему он возникает?
CORS — это стандарт, который позволяет веб-страницам получать данные с другого домена, отличного от того, с которого была загружена страница. Браузеры реализуют политику одинакового происхождения (Same-Origin Policy), которая по умолчанию блокирует межсайтовые запросы. CORS — это способ ослабить эту политику контролируемым образом.
Важно понимать: CORS проверяется браузером, а не сервером. Сервер лишь отправляет специальные заголовки в ответе, а браузер решает, разрешить ли доступ к данным.
Типичный сценарий ошибки в React + Axios
Вы запускаете React-приложение на localhost:3000 и пытаетесь сделать запрос к API на example.com:
axios.get('https://api.example.com/data')
.then(response => console.log(response))
.catch(error => console.error(error));
Браузер сначала отправляет предварительный запрос (preflight) методом OPTIONS, чтобы проверить разрешения. Если сервер не отвечает правильными заголовками CORS, запрос блокируется.
Способы решения на стороне клиента (React/Axios)
1. Прокси в development-режиме (Create React App)
Самый простой способ обойти CORS во время разработки — использовать встроенный прокси в Create React App. Добавьте в файл package.json:
"proxy": "https://api.example.com"
Теперь все запросы к неизвестным маршрутам будут перенаправляться через прокси:
// Вместо axios.get('https://api.example.com/data')
axios.get('/data') // Запрос пойдет на localhost:3000/data, а прокси перенаправит
Это работает только в development-режиме! Для продакшена нужна другая настройка.
2. Настройка кастомного прокси-сервера
Для более сложных сценариев создайте файл setupProxy.js в папке src:
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'https://api.example.com',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
})
);
};
3. Использование CORS-расширения браузера (только для разработки!)
Расширения вроде "CORS Unblock" или "Moesif CORS" могут отключать проверку CORS, но это крайне небезопасно и подходит только для локальной разработки.
Способы решения на стороне сервера (правильный подход)
1. Настройка заголовков CORS на сервере
Для Node.js с Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Разрешить все домены (небезопасно для продакшена!)
app.use(cors());
// Или настроить конкретные домены
app.use(cors({
origin: 'http://localhost:3000', // Только ваш React-домен
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
2. Настройка для разных технологий
- Nginx: Добавьте в конфиг:
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000'; - AWS API Gateway: Включите CORS в настройках метода
- Firebase: Используйте Firebase Functions с cors-пакетом
3. Обработка preflight-запросов
Убедитесь, что сервер правильно обрабатывает OPTIONS-запросы:
app.options('*', cors()); // Разрешить preflight для всех маршрутов
Продвинутые сценарии с Axios
Конфигурация экземпляра Axios с credentials
Если нужно отправлять куки или авторизационные заголовки:
const api = axios.create({
baseURL: 'https://api.example.com',
withCredentials: true // Важно! Сервер должен разрешить credentials
});
Сервер должен отвечать с заголовком: Access-Control-Allow-Credentials: true и конкретным origin (не "*").
Обработка ошибок CORS в React
axios.get('https://api.example.com/data')
.then(response => {
// Обработка успешного ответа
})
.catch(error => {
if (error.response) {
// Сервер ответил с ошибкой
} else if (error.request) {
// Запрос был сделан, но ответа нет (возможно, CORS)
console.error('CORS или сетевая ошибка:', error.message);
} else {
// Что-то пошло не так при настройке запроса
}
});
Безопасность и лучшие практики
- Никогда не используйте
Access-Control-Allow-Origin: *с credentials - В продакшене всегда указывайте конкретные разрешенные домены
- Используйте environment variables для хранения URL API
- Рассмотрите использование API Gateway или BFF (Backend For Frontend) паттерна
Для production-среды настройте CORS максимально строго. Разрешайте только необходимые методы и заголовки, и только с доверенных доменов.
FAQ: Часто задаваемые вопросы
Почему CORS ошибка возникает только в браузере?
CORS — это механизм безопасности браузеров. Запросы из Postman, cURL или Node.js-сервера не подвержены этим ограничениям.
Как отладить CORS ошибку?
Откройте DevTools → Вкладка Network. Найдите запрос с ошибкой, проверьте заголовки ответа (Response Headers). Убедитесь, что присутствуют Access-Control-Allow-Origin и другие CORS-заголовки.
Можно ли отключить CORS полностью?
Нет, это встроенная функция безопасности браузеров. Можно временно отключить для локальной разработки с помощью специальных флагов запуска браузера, но это не рекомендуется.
Работает ли прокси из package.json в продакшене?
Нет, эта функция работает только в development-сервере Create React App. Для продакшена нужен настоящий прокси-сервер (Nginx, Apache, облачный прокси).
Как настроить CORS для нескольких доменов?
На сервере нужно динамически проверять заголовок Origin и, если он в белом списке, возвращать его значение в Access-Control-Allow-Origin.