Что такое CORS (Cross-Origin Resource Sharing)?

Ответ

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

Как это работает на практике:

  1. Простой запрос (Simple Request): Для GET, POST (с определенными типами контента) и HEAD браузер сразу отправляет запрос с заголовком Origin. Сервер должен ответить с заголовком Access-Control-Allow-Origin, содержащим разрешенный домен или *.
  2. Предварительный запрос (Preflight Request): Для "непростых" методов (например, PUT, DELETE) или запросов с кастомными заголовками браузер сначала отправляет запрос OPTIONS. Сервер должен ответить, какие методы, заголовки и домены разрешены.

Пример конфигурации CORS на стороне сервера (Node.js/Express):

const express = require('express');
const app = express();

// Middleware для обработки CORS
app.use((req, res, next) => {
    // Разрешаем запросы с конкретного домена
    res.header('Access-Control-Allow-Origin', 'https://my-frontend-app.com');
    // Разрешаем необходимые методы
    res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    // Разрешаем необходимые заголовки
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    // Разрешаем отправку кук/учетных данных
    res.header('Access-Control-Allow-Credentials', 'true');

    // Обрабатываем предварительный OPTIONS-запрос
    if (req.method === 'OPTIONS') {
        return res.sendStatus(200);
    }
    next();
});

Ключевые моменты:

  • Заголовок Access-Control-Allow-Origin: * несовместим с Access-Control-Allow-Credentials: true.
  • CORS — это политика браузера, а не сервера. Сервер лишь сообщает браузеру свои правила.
  • Для отладки можно использовать расширения, временно отключающие CORS, но в продакшене конфигурация обязательна.

Ответ 18+ 🔞

Слушай, вот объясню тебе про CORS, чтобы ты не охуевал потом, когда твой фронтенд начнёт материться на бэкенд. Это, блядь, такая хитрая жопа в браузерах, чтобы один сайт не мог просто так, с бухты-барахты, тырить данные с другого сайта.

Представь: твоя страничка с my-cool-site.com пытается через fetch дернуть API на super-secret-api.com. Браузер такой: «Стоп, ёпта! А ты кто такой?» И по умолчанию он этот запрос заблокирует, как назойливого мартышлюшку. Вот чтобы этого не было, и нужен CORS — это когда сервер сам говорит браузеру: «Да, пусть этот чувак с my-cool-site.com ко мне лезет, я разрешаю».

Как эта магия происходит:

  1. Простой запрос (Simple Request): Это когда ты делаешь обычный GET или POST. Браузер сразу шлёт запрос, но пристёгивает к нему заголовок Origin — типа, «я с такого-то дома». Сервер в ответ должен крикнуть: Access-Control-Allow-Origin: https://my-cool-site.com (или звёздочку *, если он всем похуй). Если этого заголовка нет — всё, приехали, браузер тебе ошибку в консоль вывалит, и доверия ебать ноль.
  2. Предварительный запрос (Preflight Request): А вот это уже ёперный театр! Если твой запрос нестандартный — скажем, метод PUT, DELETE или ты кастомные заголовки цепляешь — браузер сначала, на всякий случай, отправляет «разведывательный» запрос методом OPTIONS. Мол, «сервак, а можно так-то?». И сервер должен внятно ответить: какие методы разрешены, какие заголовки, и с каких доменов можно. Только после этого браузер пошнёт настоящий запрос.

Вот как это выглядит в коде на Node.js с Express, чтобы не быть распиздяем:

const express = require('express');
const app = express();

// Ставим промежуточный софт (middleware), который будет обрабатывать этот CORS
app.use((req, res, next) => {
    // Разрешаем запросы ТОЛЬКО с нашего фронтенда. Не со всех подряд!
    res.header('Access-Control-Allow-Origin', 'https://my-frontend-app.com');
    // Говорим, какие методы мы вообще понимаем
    res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    // Разрешаем определённые заголовки, которые фронт может слать
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    // Важный момент! Если куки или авторизационные заголовки нужны — включаем это
    res.header('Access-Control-Allow-Credentials', 'true');

    // Если это тот самый предварительный OPTIONS-запрос — сразу отвечаем "ок" и не грузим дальше
    if (req.method === 'OPTIONS') {
        return res.sendStatus(200);
    }
    // Если не OPTIONS — иди дальше, обрабатывай основной запрос
    next();
});

Запомни раз и навсегда, а то будет тебе хиросима:

  • Если поставил Access-Control-Allow-Credentials: true (чтобы куки таскать), то в Allow-Origin нельзя писать звёздочку *. Надо явно домен указать. Иначе браузер опять охуеет и ничего не даст.
  • CORS — это не серверная штука, а браузерная. Сервер просто вежливо сообщает браузеру свои правила. Сам-то сервер, будь он неладен, запрос примет и обработает, если до него дойти.
  • Да, для локальной отладки можно поставить расширение, которое CORS отключает. Но это как ехать на машине с отключёнными тормозами — только для теста в чистом поле. В продакшене так делать — это ядрёна вошь, сразу накроешься медным тазом. Настраивай правильно.