Перейти к содержанию
Innovialabs

CORS: почему возникает ошибка и как её исправить

Практика3 мин

Коротко

Ошибку CORS выдаёт браузер, а не сервер — она исправляется на сервере, который должен явно разрешить ваш origin нужными заголовками, а не отключением защиты.

Почему появляется ошибка CORS

Браузер следует same-origin policy: JavaScript на странице может свободно читать ответы только со своего origin — сочетания протокола, домена и порта. https://site.uz и https://api.site.uz — разные origin, как и http://localhost:3000 и http://localhost:8080.

CORS (Cross-Origin Resource Sharing) — механизм, через который сервер говорит браузеру: «Этому origin можно читать мои ответы». Если нужного заголовка нет, браузер блокирует ответ и пишет ошибку в консоль.

Важно: запрос часто доходит до сервера и выполняется. Браузер лишь не отдаёт результат вашему коду. Поэтому Postman и curl работают — у них нет CORS.

Простые запросы и preflight

Некоторые запросы браузер отправляет сразу: GET, HEAD или POST с «простыми» заголовками и типами вроде application/x-www-form-urlencoded.

Для остальных — например, PUT, DELETE, POST с Content-Type: application/json или с заголовком Authorization — браузер сначала шлёт preflight: запрос OPTIONS с вопросом, можно ли.

OPTIONS /orders HTTP/1.1
Origin: https://site.uz
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, authorization

Сервер должен ответить успешным статусом и разрешающими заголовками. Только после этого уйдёт основной запрос.

Какие заголовки нужны

ЗаголовокЗачем
Access-Control-Allow-OriginКакой origin может читать ответ
Access-Control-Allow-MethodsКакие методы разрешены (для preflight)
Access-Control-Allow-HeadersКакие заголовки запроса разрешены
Access-Control-Allow-CredentialsМожно ли передавать cookie
Access-Control-Max-AgeСколько кешировать ответ на preflight
Vary: OriginЧтобы кеш не отдал ответ для чужого origin

Как исправить правильно

Настройте сервер на белый список origin. Пример для Express:

import express from "express";
import cors from "cors";

const app = express();
const allowed = ["https://site.uz", "https://admin.site.uz"];

app.use(cors({
  origin: (origin, cb) => cb(null, !origin || allowed.includes(origin)),
  credentials: true,
  methods: ["GET", "POST", "PUT", "DELETE"],
  allowedHeaders: ["Content-Type", "Authorization"],
}));

Если CORS настраивается в nginx, убедитесь, что запрос OPTIONS получает ответ с заголовками, а не уходит в приложение, которое возвращает 404 или 401.

Чтобы браузер отправил cookie на другой origin, нужно с двух сторон:

  • на клиенте fetch(url, { credentials: "include" });
  • на сервере Access-Control-Allow-Credentials: true и конкретный origin в Access-Control-Allow-Origin.

Значение * вместе с credentials браузер не примет. Кроме того, cookie для кросс-сайтовых запросов должны иметь SameSite=None; Secure.

Опасные «решения»

  • Отражать любой Origin вместе с credentials. Тогда любой сайт сможет делать запросы от имени залогиненного пользователя.
  • * для приватного API. Допустимо только для публичных данных без авторизации.
  • Расширения браузера и флаги, отключающие CORS. Работает только у вас, пользователи всё равно увидят ошибку.
  • Чужие публичные прокси. Ваши данные идут через сторонний сервер.

Хорошая альтернатива — один origin: отдавать фронтенд и API с одного домена через reverse proxy или dev-proxy сборщика. Тогда CORS не нужен вовсе.

Как диагностировать

  1. Откройте вкладку Network и найдите запрос OPTIONS.
  2. Проверьте его статус: он должен быть успешным, а не 404, 401 или 500.
  3. Сравните Origin запроса со значением Access-Control-Allow-Origin — они должны совпадать посимвольно, включая протокол и порт.
  4. Проверьте, не теряются ли заголовки при ошибке: многие серверы не добавляют CORS к ответам 4xx и 5xx, и реальная ошибка маскируется под CORS.

Частые вопросы

CORS — правило браузера. Postman и серверные запросы его не проверяют, поэтому они видят ответ, а браузер скрывает его от скрипта.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.