Что такое CORS и как его решать во фронтенде?

MiddleJavaScript · Frontend·Обновлено 20 июля 2026
Коротко
CORS (Cross-Origin Resource Sharing) — механизм браузера, ограничивающий HTTP-запросы к другому домену из соображений безопасности. Решается настройкой заголовков на сервере, использованием прокси или JSONP для legacy-случаев.

Что такое CORS

CORS (Cross-Origin Resource Sharing) — это механизм безопасности браузера, реализующий политику одного источника (Same-Origin Policy). Браузер блокирует запросы из JavaScript к ресурсам на другом origins, если сервер явно не разрешил это через специальные HTTP-заголовки.

Origin состоит из трёх компонентов: протокол, домен и порт. Если хотя бы один отличается — это cross-origin запрос.

https://app.com → https://api.app.com   // разные домены — CORS
https://app.com → http://app.com        // разные протоколы — CORS
https://app.com:3000 → https://app.com  // разные порты — CORS

Как работает CORS

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

Для GET/POST запросов с ограниченными заголовками браузер сразу отправляет запрос, но проверяет ответный заголовок Access-Control-Allow-Origin.

Preflight-запросы

Для «сложных» запросов (PUT, DELETE, кастомные заголовки, JSON-тело) браузер сначала отправляет OPTIONS-запрос — preflight. Сервер должен ответить разрешающими заголовками, иначе основной запрос не уйдёт.

Решения

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

Сервер должен вернуть заголовки:

Access-Control-Allow-Origin: https://app.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true

2. Прокси на уровне dev-сервера (для разработки)

// next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        // Все запросы /api/* проксируются на бэкенд
        destination: 'http://localhost:4000/:path*',
      },
    ];
  },
};

Или в Vite:

// vite.config.ts
export default {
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:4000',
        changeOrigin: true,
        // Убираем префикс /api при проксировании
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
};

3. Credentials и куки

Если нужно передавать cookies или Authorization, на фронтенде обязательно:

// fetch — указываем include для передачи куки
fetch('https://api.example.com/data', {
  credentials: 'include',
});

// axios — аналогично
axios.get('https://api.example.com/data', {
  withCredentials: true,
});

При этом сервер не может вернуть Access-Control-Allow-Origin: * — только конкретный origin.

4. CORS в production

В продакшене прокси настраивается на уровне nginx или API-gateway:

add_header Access-Control-Allow-Origin "https://app.com";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";

Важные нюансы

  • CORS — это браузерный механизм. curl и Postman его не соблюдают.
  • Access-Control-Allow-Origin: * несовместим с credentials: 'include'.
  • Preflight кэшируется через Access-Control-Max-Age.
  • Ошибка CORS в консоли означает проблему на сервере, а не на фронтенде.

Что хочет услышать интервьюер

Кандидат понимает, что CORS — это браузерная политика безопасности, а не серверная ошибка

Знает разницу между simple request и preflight (OPTIONS)

Понимает, что решение CORS — это настройка заголовков на сервере, а не на фронтенде

Умеет настраивать прокси в dev-окружении (Vite, Webpack, Next.js)

Знает про credentials и почему Access-Control-Allow-Origin: * несовместим с куками

Пример: Preflight и credentials с fetch

// Запрос с кастомным заголовком вызовет preflight
async function fetchUserData(token: string) {
  const response = await fetch('https://api.example.com/user', {
    method: 'GET',
    // Этот заголовок делает запрос «сложным» — браузер пошлёт preflight
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    // Передаём куки и credentials вместе с запросом
    credentials: 'include',
  });

  if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`);
  }

  return response.json();
}

Пример: Прокси в Vite для обхода CORS при разработке

// vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  server: {
    proxy: {
      // Все запросы на /api/* уходят на бэкенд
      '/api': {
        target: 'http://localhost:4000',
        changeOrigin: true,
        // Убираем /api из пути: /api/users → /users
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
});

Типичные ошибки

Думают, что CORS можно «починить» только на фронтенде без изменений на сервере

Путают preflight-запрос с основным запросом и не понимают, зачем браузер шлёт OPTIONS

Используют Access-Control-Allow-Origin: * в связке с credentials: 'include' и удивляются ошибке

Пытаются отключить CORS в браузере (флаги) как «решение» в продакшене

Не знают разницы между режимом разработки (прокси) и продакшен-конфигурацией

Лучшие курсы по теме

изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Feature-Sliced Design

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.5
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее