Введение
Вы запускаете свое приложение, открываете консоль браузера и видите красную ошибку:
Access to fetch at 'https://api.example.com/data' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.
Знакомо? Это одна из самых частых ошибок в веб-разработке. По статистике, с ней сталкивается каждый frontend разработчик в первые месяцы работы, и даже опытные разработчики регулярно натыкаются на проблемы с CORS.
В этой статье вы узнаете:
- ✅ Что такое CORS и почему он нужен
- ✅ Почему возникает эта ошибка
- ✅ 5 способов решить проблему (от простых до профессиональных)
- ✅ Когда какой способ использовать
- ✅ Как не создать дыру в безопасности
📋 Содержание
Что такое CORS
CORS (Cross-Origin Resource Sharing) — это механизм безопасности браузера, который контролирует, какие веб-сайты могут отправлять запросы к вашему API.
Простыми словами:
Представьте, что ваш браузер — это охранник на входе в здание (API). CORS — это список гостей, которым разрешен вход. Если сайт не в списке, охранник не пустит его запрос внутрь.
Технические детали
CORS работает через HTTP заголовки. Когда браузер делает запрос к другому домену, он проверяет:
- Origin — откуда идет запрос (
http://localhost:3000) - Access-Control-Allow-Origin — кому разрешен доступ (приходит от сервера)
Если они не совпадают → ошибка CORS.
Что считается "другим доменом"
Запрос будет считаться cross-origin, если отличается любое из:
| Параметр | Пример 1 | Пример 2 | Cross-Origin? |
|---|---|---|---|
| Протокол | http:// |
https:// |
✓ Да |
| Домен | example.com |
api.example.com |
✓ Да |
| Порт | :3000 |
:8080 |
✓ Да |
| Все одинаково | http://localhost:3000 |
http://localhost:3000 |
✗ Нет |
Важно: Даже localhost:3000 → localhost:8000 будет cross-origin!
Почему возникает ошибка
Главная причина: Браузер защищает пользователя
CORS не дает злоумышленникам:
- Читать ваши cookie с других сайтов
- Делать запросы от вашего имени
- Красть токены авторизации
Типичный сценарий ошибки:
1. Frontend на localhost:3000 (разработка)
2. API на api.example.com (или localhost:8000)
3. Разные origin → CORS блокирует запрос
Пример кода, который вызывает ошибку:
// Ваш React/Vue/Angular код
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('CORS Error:', error));
// ❌ Результат в консоли:
// Access to fetch... has been blocked by CORS policy
⚠️ Почему в production работает, а в dev нет?
В production:
- Frontend:
https://myapp.com - API:
https://myapp.com/api - Один origin → CORS не нужен ✓
В разработке:
- Frontend:
http://localhost:3000 - API:
http://localhost:8000 - Разные origin → CORS нужен ✗
5 способов решения
Рассмотрим все способы от простых до production-ready. Для каждого — примеры кода, плюсы и минусы.
Способ 1: Настройка Backend (временное решение)
Идея: Настроить сервер, чтобы он разрешал запросы с вашего localhost.
Для Node.js (Express):
// backend/server.js
const express = require('express');
const cors = require('cors');
const app = express();
// ⚠️ Только для разработки!
app.use(cors({
origin: 'http://localhost:3000',
credentials: true
}));
// Или разрешить всем (очень небезопасно):
// app.use(cors());
app.get('/api/users', (req, res) => {
res.json({ users: ['Alice', 'Bob'] });
});
app.listen(8000);
Для Python (Flask):
# backend/app.py
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
# Только для разработки!
CORS(app, origins=['http://localhost:3000'])
@app.route('/api/users')
def get_users():
return {'users': ['Alice', 'Bob']}
if __name__ == '__main__':
app.run(port=8000)
✅ Плюсы
- Быстро настроить
- Работает сразу
- Контролируете доступ
❌ Минусы
- Нужен доступ к backend
- Если backend не ваш — не сработает
- Нужно менять для production
- Риск забыть убрать
cors()
🎯 Когда использовать:
- У вас есть свой backend
- Это временное решение для разработки
- Команда понимает риски
Способ 2: Proxy в Webpack/Vite
Идея: Настроить dev-сервер так, чтобы он пересылал запросы к API. Браузер думает, что запрос идет к тому же origin.
Для Vite (Vue, React с Vite):
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})
Использование:
// Вместо:
fetch('http://localhost:8000/users')
// Пишем:
fetch('/api/users') // ✓ Proxy перенаправит на localhost:8000/users
Для Create React App:
// package.json
{
"proxy": "http://localhost:8000"
}
Для Vue CLI:
// vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
✅ Плюсы
- Не нужен доступ к backend
- Работает с любым API (даже внешним)
- Безопасно (proxy только в dev)
- Код не меняется для production
❌ Минусы
- Нужна настройка для каждого проекта
- Только для разработки
- Сложнее дебажить запросы
🎯 Когда использовать:
- Backend не ваш или недоступен для настройки
- Работаете с внешним API
- Хотите не менять код для production
Способ 3: Browser Extensions (не рекомендуется)
Идея: Установить расширение, которое отключает CORS в браузере.
Популярные расширения:
- Allow CORS: Access-Control-Allow-Origin
- CORS Unblock
- Moesif Origin & CORS Changer
✅ Плюсы
- Очень быстро (2 минуты)
- Не нужно ничего настраивать
- Работает с любым API
❌ Минусы
- ОЧЕНЬ небезопасно
- Работает только у вас
- Легко забыть выключить
- Не подходит для команды
⚠️ НИКОГДА НЕ ИСПОЛЬЗУЙТЕ В PRODUCTION
Это создаст дыру в безопасности! Ваши cookie и токены будут уязвимы!
🎯 Когда использовать:
- Быстрое тестирование (5 минут)
- Нет времени настраивать proxy
- ТОЛЬКО на своей машине
- ТОЛЬКО для тестирования
Способ 4: Mock API с правильными CORS
Идея: Использовать Mock API сервис, который уже настроен с правильными CORS заголовками.
Зачем это нужно?
Часто проблема не в том, что backend не настроен, а в том, что backend еще не готов. Вместо ожидания можно использовать Mock API.
Пример с LightBox API:
- Создаем Mock API (2 минуты): регистрируемся на lightboxapi.ru, создаем endpoint
GET /api/users - Настраиваем ответ в веб-интерфейсе
- Используем в коде:
// React example
import { useEffect, useState } from 'react';
function Users() {
const [users, setUsers] = useState([]);
useEffect(() => {
// ✓ CORS уже настроен правильно!
fetch('https://yourdomain.lightboxapi.ru/your-workspace/users')
.then(res => res.json())
.then(data => setUsers(data.users))
.catch(err => console.error(err));
}, []);
return (
{users.map(user => (
- {user.name}
))}
);
}
Преимущества Mock API:
| Особенность | Mock API | Proxy | Backend настройка |
|---|---|---|---|
| Не нужен backend | ✓ | ✓ | ✗ |
| CORS настроен | ✓ | ✓ | Нужно настраивать |
| Работа в команде | ✓ | ✗ | ✓ |
| Логирование запросов | ✓ | ✗ | ✓ |
✅ Плюсы
- Не нужен backend (можно начать разработку сразу)
- CORS уже настроен правильно
- Команда работает с одним API
- Логирование всех запросов
- Легко создать разные сценарии
❌ Минусы
- Нужна регистрация в сервисе
- Бесплатный план может иметь ограничения
- Зависимость от внешнего сервиса
🎯 Когда использовать:
- Backend еще не готов
- Нужно начать frontend разработку прямо сейчас
- Команда работает параллельно
- Хотите тестировать разные сценарии
Способ 5: Production решение
Идея: Правильная архитектура, которая работает в production без CORS проблем.
Архитектура 1: Same Origin (тот же домен)
Nginx конфигурация:
server {
listen 80;
server_name myapp.com;
# Frontend (статика)
location / {
root /var/www/frontend/build;
try_files $uri /index.html;
}
# Backend API (proxy)
location /api/ {
proxy_pass http://localhost:8000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Результат:
- Frontend:
https://myapp.com - API:
https://myapp.com/api - Один origin → нет CORS! ✓
Архитектура 2: Subdomain с CORS
Backend настройка (production):
// Node.js
app.use(cors({
origin: [
'https://myapp.com',
'https://app.myapp.com'
],
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
✅ Плюсы
- Безопасно
- Масштабируемо
- Нет CORS проблем
- Production-ready
❌ Минусы
- Требует настройки инфраструктуры
- Нужны знания DevOps
- Дольше настраивать
🎯 Когда использовать:
- Production окружение
- Долгосрочный проект
- Нужна масштабируемость
- Есть DevOps команда
Когда использовать какой подход
| Ситуация | Рекомендуемый способ | Альтернатива |
|---|---|---|
| 🚀 Быстрое тестирование (5 мин) | Browser Extension | Proxy |
| 💻 Локальная разработка | Proxy (Vite/Webpack) | Backend настройка |
| 🏗️ Backend не готов | Mock API | Proxy + JSON файлы |
| 👥 Командная разработка | Mock API | Backend с CORS |
| 🎯 Production | Same Origin / API Gateway | Subdomain + CORS |
Вопросы безопасности
⚠️ Частые ошибки безопасности
Ошибка 1: Access-Control-Allow-Origin: *
Плохо:
app.use(cors({
origin: '*', // ❌ Разрешает ВСЕМ
credentials: true
}));
Почему плохо:
- Любой сайт может делать запросы к вашему API
- Риск CSRF атак
- Утечка cookies и токенов
Хорошо:
app.use(cors({
origin: ['https://myapp.com'], // ✓ Только доверенные
credentials: true
}));
✅ Best Practices
- Development:
- Используйте Proxy или Mock API
- Никогда не используйте Browser Extensions в команде
- Документируйте настройки
- Production:
- Whitelist только доверенные домены
- Используйте HTTPS
- Логируйте все CORS errors
FAQ
❓ Почему CORS работает в Postman, но не в браузере?
Ответ: Postman не браузер, он не применяет CORS политику. Браузер защищает пользователя, Postman нет.
Postman → API: ✓ Работает (нет CORS)
Браузер → API: ✗ Блокировка (CORS защищает)
❓ Можно ли полностью отключить CORS?
Ответ: Нет в браузере, да на сервере (но не надо). CORS — это защита браузера, вы не можете ее отключить. Но можете настроить сервер, чтобы он разрешал запросы.
❓ Почему GET работает, а POST нет?
Ответ: POST требует preflight request (OPTIONS). Сервер должен отвечать на OPTIONS запросы:
app.options('*', cors()); // Разрешить preflight
app.use(cors());
❓ Нужен ли CORS для мобильного приложения?
Ответ: Нет. CORS — это политика браузера. Мобильные приложения (React Native, Flutter) не подвержены CORS.
Заключение
📝 Краткая памятка:
| Этап | Решение | Время настройки |
|---|---|---|
| Быстрый тест | Browser Extension | 2 минуты |
| Локальная разработка | Proxy (Vite/Webpack) | 5-10 минут |
| Backend не готов | Mock API | 5 минут |
| Командная работа | Mock API / Backend CORS | 10-20 минут |
| Production | Same Origin / Gateway | 30-60 минут |
💡 Главный совет:
Не боритесь с CORS, работайте с ним.
CORS существует для вашей безопасности. Понимание того, как он работает, сэкономит вам часы отладки.
🎯 Попробуйте LightBox API
Хотите начать разработку прямо сейчас, не дожидаясь backend?
LightBox API — это Mock API сервис с правильными CORS настройками из коробки.
- ✓ Импорт Swagger/Postman за 2 минуты
- ✓ Логирование всех запросов
- ✓ Разные сценарии ответов
- ✓ Бесплатный план для старта
Статья обновлена: 19 октября 2025
Автор: LightBox API Team