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

Ответ

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

Проблема, которую решает CORS: Браузер по умолчанию блокирует межсайтовые HTTP-запросы, инициированные скриптами (например, вызовы API с fetch или XMLHttpRequest), в соответствии с политикой Same-Origin Policy. CORS позволяет серверу явно объявить, какие внешние источники имеют право на доступ к его ресурсам.

Как это работает:

  1. Для простых запросов (GET, POST, HEAD с определенными заголовками) браузер добавляет заголовок Origin, а сервер отвечает с заголовком Access-Control-Allow-Origin.
  2. Для непростых запросов (например, с пользовательскими заголовками или методом PUT) браузер сначала отправляет предзапрос (preflight) методом OPTIONS, чтобы проверить разрешения сервера.

Пример заголовков ответа сервера (C# ASP.NET Core):

// В Startup.cs или Program.cs
app.UseCors(builder =>
    builder.WithOrigins("https://trusted-site.com")
           .AllowAnyMethod()
           .AllowAnyHeader());

Или более детальная настройка через middleware:

app.Use(async (context, next) =>
{
    context.Response.Headers.Add("Access-Control-Allow-Origin", "https://my-frontend.com");
    context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
    context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization");

    if (context.Request.Method == "OPTIONS")
    {
        context.Response.StatusCode = 200;
        return;
    }
    await next();
});

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

  • CORS контролируется сервером, а не клиентом.
  • Это защита в браузере. Инструменты вроде Postman или curl не применяют политику CORS.
  • Для работы с учетными данными (куки, заголовки авторизации) необходимо также установить Access-Control-Allow-Credentials: true на сервере, а на клиенте — credentials: 'include'.

Ответ 18+ 🔞

Давай разберёмся, что за зверь такой этот CORS, а то народ с ним голову ломает, как с придурью.

В общем, представь себе: сидит браузер, такой бдительный охранник, и следит, чтобы твой фронтенд с одного сайта не шарился куда попало. Это у него называется Same-Origin Policy — политика одного источника. Типа, «сиди, сука, на своём localhost:3000 и не высовывайся». А если твоему скрипту вдруг понадобится стянуть данные с API, который на api.krutoy-servis.com живёт, браузер его нахуй пошлёт. И будет прав, в общем-то, с точки зрения безопасности.

Вот как раз чтобы этот охранник-браузер не был совсем уж тупым и беспросветным, придумали CORS (Cross-Origin Resource Sharing). Это такой механизм, где сервер сам говорит браузеру: «Эй, чувак, расслабься, вот этим ребятам с https://trusted-site.com я доверяю, пусть заходят».

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

  1. Простые запросы (обычные GET, POST). Браузер просто добавляет в запрос заголовок Origin (типа «я сюда пришёл») и ждёт, что сервер в ответе вернёт Access-Control-Allow-Origin с адресом твоего фронта или звёздочкой (*). Если не вернёт или вернёт не тот — всё, пиздец, в консоли красная ошибка, и данные тебе не видать, как своих ушей.

  2. Непростые запросы (там, где кастомные заголовки, или метод PUT/DELETE). Тут браузер, падла такая, сначала устраивает предзапрос (preflight). Он летит на сервер методом OPTIONS и спрашивает: «Мужик, можно я вот так вот и сяк?». Сервер должен ответить заголовками, что мол, да, можно тебе с такого-то Origin, такими-то методами (Allow-Methods) и такими-то заголовками (Allow-Headers). И только после этого браузер отпускает уже настоящий, основной запрос.

Сервер — всему голова. Запомни раз и навсегда: CORS настраивается НА СЕРВЕРЕ. Ты на клиенте нихуя с этим не сделаешь, кроме как правильно запрос отправить. А всякие Postman и curl эту политику вообще игнорируют — они не браузеры.

Пример, как на сервере (допустим, на ASP.NET Core) рот открывают пошире:

// Где-то в Program.cs или Startup.cs
app.UseCors(builder =>
    builder.WithOrigins("https://moy-frontend.ru") // Конкретный доверенный сайт
           .AllowAnyMethod()                       // Можно все методы (GET, POST и т.д.)
           .AllowAnyHeader());                     // Можно любые заголовки

А если ты, допустим, куки или токен авторизации в заголовке таскаешь, то тут уже не * в Allow-Origin прокатит — нужно явно свой фронтенд указывать. И ещё флаг Allow-Credentials на сервере выставить, а в клиентском fetch добавить credentials: 'include'. Иначе опять облом.

Короче, алгоритм при ошибке CORS:

  1. Не паниковать.
  2. Посмотреть в консоли браузера, какой именно запрос и на каком этапе отшибли.
  3. Идти НЕ на Stack Overflow, а К СВОЕМУ БЭКЕНДЕРУ (или самому себе в зеркало) и править заголовки ответа на сервере.
  4. Профит.

Вот и вся философия. Не так страшен чёрт, как его малюют, просто сначала мозг выносит конкретно.

Видео-ответы