CORS ошибка при разработке: 5 способов решить навсегда

← Вернуться к статьям

Введение

Вы запускаете свое приложение, открываете консоль браузера и видите красную ошибку:

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

CORS (Cross-Origin Resource Sharing) — это механизм безопасности браузера, который контролирует, какие веб-сайты могут отправлять запросы к вашему API.

Простыми словами:

Представьте, что ваш браузер — это охранник на входе в здание (API). CORS — это список гостей, которым разрешен вход. Если сайт не в списке, охранник не пустит его запрос внутрь.

Технические детали

CORS работает через HTTP заголовки. Когда браузер делает запрос к другому домену, он проверяет:

  1. Origin — откуда идет запрос (http://localhost:3000)
  2. 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:3000localhost:8000 будет cross-origin!

Почему возникает ошибка

Главная причина: Браузер защищает пользователя

CORS не дает злоумышленникам:

Типичный сценарий ошибки:

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:

В разработке:

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()

🎯 Когда использовать:

Способ 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

❌ Минусы

  • Нужна настройка для каждого проекта
  • Только для разработки
  • Сложнее дебажить запросы

🎯 Когда использовать:

Способ 3: Browser Extensions (не рекомендуется)

Идея: Установить расширение, которое отключает CORS в браузере.

Популярные расширения:

✅ Плюсы

  • Очень быстро (2 минуты)
  • Не нужно ничего настраивать
  • Работает с любым API

❌ Минусы

  • ОЧЕНЬ небезопасно
  • Работает только у вас
  • Легко забыть выключить
  • Не подходит для команды

⚠️ НИКОГДА НЕ ИСПОЛЬЗУЙТЕ В PRODUCTION

Это создаст дыру в безопасности! Ваши cookie и токены будут уязвимы!

🎯 Когда использовать:

Способ 4: Mock API с правильными CORS

Идея: Использовать Mock API сервис, который уже настроен с правильными CORS заголовками.

Зачем это нужно?

Часто проблема не в том, что backend не настроен, а в том, что backend еще не готов. Вместо ожидания можно использовать Mock API.

Пример с LightBox API:

  1. Создаем Mock API (2 минуты): регистрируемся на lightboxapi.ru, создаем endpoint GET /api/users
  2. Настраиваем ответ в веб-интерфейсе
  3. Используем в коде:
// 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
  • Логирование всех запросов
  • Легко создать разные сценарии

❌ Минусы

  • Нужна регистрация в сервисе
  • Бесплатный план может иметь ограничения
  • Зависимость от внешнего сервиса

🎯 Когда использовать:

Способ 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;
    }
}

Результат:

Архитектура 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
  • Дольше настраивать

🎯 Когда использовать:

Когда использовать какой подход

Ситуация Рекомендуемый способ Альтернатива
🚀 Быстрое тестирование (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
}));

Почему плохо:

Хорошо:

app.use(cors({
  origin: ['https://myapp.com'],  // ✓ Только доверенные
  credentials: true
}));

✅ Best Practices

  1. Development:
    • Используйте Proxy или Mock API
    • Никогда не используйте Browser Extensions в команде
    • Документируйте настройки
  2. 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 настройками из коробки.

Попробовать бесплатно →

Статья обновлена: 19 октября 2025
Автор: LightBox API Team