← Назад к вопросам

Благодаря чему появляется ошибка CORS в браузере

1.0 Junior🔥 301 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Благодаря чему появляется ошибка CORS в браузере

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

Что такое Origin (источник)

Origin состоит из трёх частей: схема (protocol) + домен (domain) + порт (port)

https://example.com:443
 ^      ^           ^
протокол домен    порт

Примеры разных Origin-ов:

https://example.com        (стандартный)
https://example.com:3000   (другой порт!)
http://example.com         (другой протокол!)
https://api.example.com    (другой домен!)
https://example.org        (совсем другой домен)

Когда появляется ошибка CORS

Same-Origin Policy - браузер разрешает запросы только на тот же Origin.

// Запрос со страницы: https://example.com

// ОК: Same-Origin
fetch('https://example.com/api/users');

// ОШИБКА CORS: Другой Origin
fetch('https://api.example.com/users');

// ОШИБКА CORS: Другой порт
fetch('https://example.com:3000/api/users');

// ОШИБКА CORS: Другой протокол
fetch('http://example.com/api/users');

Сообщение об ошибке

Access to XMLHttpRequest at 'https://api.example.com/users' 
from origin 'https://example.com' 
has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

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

Шаг 1: Браузер отправляет Preflight запрос (для небезопасных запросов)

OPTIONS /api/users HTTP/1.1
Host: api.example.com
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

Шаг 2: Сервер отвечает с CORS заголовками

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400

Шаг 3: Если заголовки ОК, браузер отправляет реальный запрос

POST /api/users HTTP/1.1
Host: api.example.com
Origin: https://example.com
Content-Type: application/json

{"name": "John"}

Примеры CORS ошибок

1. Простой GET запрос

// Страница: https://example.com

fetch('https://api.example.com/posts')
  .then(r => r.json())
  .catch(e => console.error(e));

// ОШИБКА! Потому что сервер не возвращает:
// Access-Control-Allow-Origin: https://example.com

2. POST с JSON телом

// Страница: https://example.com

fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: 'John' })
})
.catch(e => console.error(e));

// ОШИБКА CORS! Потому что:
// 1. Это "небезопасный" запрос (POST не простой)
// 2. Header Content-Type требует разрешения
// 3. Сервер должен вернуть Access-Control-Allow-* заголовки

Какие запросы простые (не требуют Preflight)

Простые запросы:

  • GET, HEAD, POST
  • Только определённые заголовки (Content-Type, Accept, Accept-Language)
  • Content-Type только: application/x-www-form-urlencoded, multipart/form-data, text/plain
// ПРОСТОЙ запрос (без Preflight)
fetch('https://api.example.com/posts');

// ПРОСТОЙ POST
fetch('https://api.example.com/posts', {
  method: 'POST',
  body: new FormData() // form-data
});

Небезопасные запросы (требуют Preflight):

  • PUT, DELETE, PATCH
  • Кастомные заголовки (Authorization, X-Custom-Header)
  • application/json Content-Type
// НЕБЕЗОПАСНЫЙ запрос (требует Preflight)
fetch('https://api.example.com/users/1', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer token123'
  }
});

// Браузер отправит OPTIONS запрос перед DELETE

Решения для CORS ошибок

1. Сервер должен установить правильные заголовки

# FastAPI
from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Content-Type", "Authorization"],
)
// Express
const cors = require('cors');

app.use(cors({
  origin: 'https://example.com',
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

2. Wildcard (разрешить всем)

Access-Control-Allow-Origin: *

Это позволяет запросам с любого Origin, но имеет ограничения (no credentials).

3. JSONP (старый способ, НЕ рекомендуется)

// Работает без CORS, но устаревший подход
function handleCallback(data) {
  console.log(data);
}

const script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=handleCallback';
document.head.appendChild(script);

4. Прокси на своём сервере

// Фронтенд запрашивает СВОЙ сервер
fetch('https://example.com/api/proxy/users')

// Свой сервер переадресовывает на api.example.com
// (нет CORS, потому что backend->backend запрос)
fetch('https://api.example.com/users')

Настройка CORS в Next.js

// app/api/users/route.ts
export async function GET(request: Request) {
  const response = await fetch('https://api.example.com/users');
  const data = await response.json();

  return new Response(JSON.stringify(data), {
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Content-Type': 'application/json'
    }
  });
}

Или использовать прокси-мидлвэр

// next.config.js
module.exports = {
  async rewrites() {
    return {
      beforeFiles: [
        {
          source: '/api/external/:path*',
          destination: 'https://api.example.com/:path*'
        }
      ]
    };
  }
};

Тогда фронтенд может запрашивать:

fetch('/api/external/users')
// Будет переадресовано на https://api.example.com/users

Отладка CORS

В DevTools:

  1. Открой Network вкладку
  2. Найди запрос, который вызвал ошибку
  3. Перейди на вкладку Response Headers
  4. Проверь наличие Access-Control-Allow-Origin

Проверка заголовков:

curl -i https://api.example.com/users
# Ищи Access-Control-Allow-Origin в ответе

Частые ошибки

Ошибка 1: Wildcard с credentials

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

Это ОШИБКА! Нельзя использовать * с credentials. Нужно явно указать Origin.

Ошибка 2: Забыли про Preflight

// Думаешь, это просто запрос
fetch('https://api.example.com/users', {
  method: 'DELETE',
  headers: { 'Authorization': 'Bearer token' }
});

// На самом деле браузер отправляет 2 запроса:
// 1. OPTIONS /users (Preflight)
// 2. DELETE /users (если Preflight OK)

Итог

  • CORS - защита браузера от межсайтовых запросов
  • Ошибка появляется, когда Origin отличается (домен, порт или протокол)
  • Сервер должен вернуть Access-Control-Allow-Origin заголовок
  • Preflight запрос (OPTIONS) отправляется для небезопасных методов
  • Решения: правильная конфигурация CORS на сервере, прокси или JSONP
Благодаря чему появляется ошибка CORS в браузере | PrepBro