CORS
Браузер не даёт JavaScript-коду со страницы одного сайта читать ответы сервера с другого адреса, пока сервер явно это не разрешит. Механизм разрешения называется CORS (Cross-Origin Resource Sharing). Если фронтенд блога работает на http://localhost:5173, а API — на http://localhost:3000, без CORS браузер заблокирует запросы.
Как выглядит проблема
Откройте страницу фронтенда и выполните в консоли браузера запрос к API:
// консоль браузера на http://localhost:5173
const response = await fetch('http://localhost:3000/posts');
console.log(await response.json());В консоли появится ошибка со словами «blocked by CORS policy». Сервер при этом получил запрос и ответил — блокирует именно браузер. curl и другие серверы CORS не проверяют.
Установка
npm install @fastify/corsПодключение
Разрешите запросы с адреса фронтенда в src/app.js:
// src/app.js
import cors from '@fastify/cors';
app.register(cors, {
origin: 'http://localhost:5173',
});Повторите запрос в консоли — теперь выведется список статей. Плагин добавляет к ответам заголовок Access-Control-Allow-Origin, по которому браузер понимает, что чтение разрешено.
Методы и заголовки
Перед запросами PUT, DELETE и запросами с заголовком Authorization браузер сначала отправляет проверочный запрос OPTIONS. Плагин отвечает на него сам, но разрешённые методы лучше перечислить явно:
// src/app.js
app.register(cors, {
origin: ['http://localhost:5173', 'https://blog.example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
});Теперь фронтенд и с локального адреса, и с рабочего домена может создавать и удалять статьи с токеном.
Основные опции
| Опция | Что задаёт |
|---|---|
origin | Разрешённые адреса: строка, массив или true для любых |
methods | Разрешённые HTTP-методы |
allowedHeaders | Заголовки, которые может прислать клиент |
credentials | Разрешить отправку cookie |
maxAge | Сколько секунд браузер помнит ответ на OPTIONS |
Адреса удобно держать в .env, чтобы на сервере указать настоящий домен.
Частая ошибка
origin: true или '*' разрешает читать API с любого сайта. Для открытого API это нормально, но если API работает с токенами или cookie, перечисляйте только свои адреса — иначе чужая страница сможет отправлять запросы от имени ваших пользователей.