CORS
Браузер защищает посетителей: скрипт со страницы одного сайта не может просто так прочитать ответ другого. Сайт определяется источником (origin) — схемой, доменом и портом. CORS (Cross-Origin Resource Sharing) — правила, по которым сервер сообщает браузеру, каким чужим источникам можно читать его ответы.
Когда это нужно
Допустим, фронтенд блога на React работает на http://localhost:5173, а API — на http://localhost:3000. Порты разные, значит, и источники разные. Скрипт фронтенда делает запрос:
// src/main.js (фронтенд)
const response = await fetch('http://localhost:3000/api/posts');
const posts = await response.json();
console.log(posts);Сервер ответит, но браузер не отдаст ответ скрипту, а напишет в консоли ошибку со словами blocked by CORS policy. Запрос из curl или с другого сервера при этом работает: CORS проверяет только браузер.
Установка
npm install corsРазрешаем один источник
Подключите middleware в src/app.js для адресов API:
// src/app.js
import cors from 'cors';
app.use('/api', cors({ origin: 'http://localhost:5173' }));Middleware добавит к ответам заголовок Access-Control-Allow-Origin: http://localhost:5173. Обновите страницу фронтенда — в консоли появится массив статей.
Несколько источников
В origin можно передать массив — например, адрес для разработки и рабочий домен:
// src/app.js
app.use('/api', cors({
origin: ['http://localhost:5173', 'https://example.com'],
methods: ['GET', 'POST', 'PATCH', 'DELETE'],
}));Запросы с других сайтов браузер по-прежнему заблокирует.
Предварительный запрос
Перед «непростыми» запросами — например, DELETE или POST с JSON и заголовком Authorization — браузер сначала сам отправляет запрос методом OPTIONS. Он спрашивает сервер, разрешён ли такой запрос. Middleware cors отвечает на него сама, если подключена через app.use(): дополнительный код писать не нужно.
| Заголовок ответа | Что разрешает |
|---|---|
Access-Control-Allow-Origin | Читать ответ указанному источнику |
Access-Control-Allow-Methods | Использовать перечисленные методы |
Access-Control-Allow-Headers | Отправлять перечисленные заголовки |
Access-Control-Allow-Credentials | Отправлять cookie |
Cookie с другого источника
Если фронтенд должен отправлять cookie сессии, нужны две вещи: опция credentials: true в cors() на сервере и credentials: 'include' в fetch() на клиенте. С токеном JWT в заголовке Authorization этого не требуется.
Частая ошибка
Вызов cors() без опций разрешает запросы с любого сайта. Для открытого API только для чтения это допустимо, но для адресов, которые меняют данные, — нет. Всегда перечисляйте свои источники в origin. И помните: CORS не заменяет авторизацию — он ограничивает только браузеры, а программы могут обратиться к API напрямую.