Библиотека CORS для JavaScript (Node.js): Полное руководство
1. Что это и зачем нужна
CORS (Cross-Origin Resource Sharing) — это механизм безопасности, реализованный в браузерах, который контролирует доступ к ресурсам (API, шрифтам, скриптам) с веб-страниц, загруженных с другого домена (origin). По умолчанию браузеры блокируют HTTP-запросы, инициированные скриптами (например, через fetch или XMLHttpRequest), если они направлены на домен, отличный от того, с которого была загружена страница. Это предотвращает атаки типа CSRF (Cross-Site Request Forgery) и утечку данных.
Библиотека cors для Node.js и Express — это middleware (промежуточное ПО), которое позволяет разработчикам легко настраивать и управлять CORS-политиками на серверной стороне. Вместо ручного написания заголовков (Access-Control-Allow-Origin, Access-Control-Allow-Methods и т.д.) и обработки предварительных запросов (preflight requests с методом OPTIONS), эта библиотека автоматизирует весь процесс. Она интегрируется в цепочку обработки запросов Express и добавляет необходимые заголовки к ответам.
Зачем это нужно? Если вы разрабатываете API на Node.js, которое будет использоваться фронтенд-приложением (React, Vue, Angular), мобильным приложением или сторонним сервисом, работающим с другого домена (например, api.mysite.com для app.mysite.com), вам обязательно нужно настроить CORS. Без этого браузер просто заблокирует запросы, и пользователь увидит ошибку в консоли. Библиотека cors делает эту настройку гибкой, безопасной и простой.
2. Установка
Установка производится через менеджер пакетов npm (Node Package Manager). Убедитесь, что у вас установлен Node.js и npm.
npm install cors
После установки пакет будет добавлен в node_modules, а запись о нем появится в файле package.json.
Если вы используете yarn:
yarn add cors
3. Быстрый старт — минимальный рабочий пример
Самый простой способ использовать CORS — включить его для всех запросов. Это подходит для разработки или публичных API, где доступ разрешен с любого домена.
const express = require('express');
const cors = require('cors');
const app = express();
// Включаем CORS для всех маршрутов
app.use(cors());
app.get('/api/data', (req, res) => {
res.json({ message: 'Этот ответ разрешен для всех источников!' });
});
app.listen(3000, () => {
console.log('Сервер запущен на порту 3000');
});
В этом примере любой запрос с любого домена (например, с http://localhost:8080 или https://example.com) к /api/data будет успешно обработан. Браузер не заблокирует ответ.
4. Основные методы/функции/классы
Библиотека cors предоставляет одну основную функцию — cors(options), которая возвращает middleware-функцию. Однако, настройки передаются через объект options, что дает огромную гибкость. Рассмотрим 8 ключевых опций и методов.
4.1. cors() — базовая конфигурация (все разрешено)
Сигнатура: cors(options?: CorsOptions)
Что делает: Создает middleware, который добавляет заголовки CORS к ответу. Без аргументов разрешает доступ с любого источника (*), любые методы и заголовки.
const cors = require('cors');
// Разрешаем все
app.use(cors());
4.2. origin — настройка разрешенных источников
Сигнатура: origin: string | string[] | RegExp | Function
Что делает: Определяет, какие домены могут получать доступ к ресурсам. Можно указать конкретный домен, список доменов, регулярное выражение или функцию для динамической проверки.
// Разрешаем только один домен
app.use(cors({ origin: 'https://myfrontend.com' }));
// Разрешаем несколько доменов
app.use(cors({ origin: ['https://site1.com', 'https://site2.com'] }));
// Разрешаем все поддомены example.com
app.use(cors({ origin: /\.example\.com$/ }));
// Динамическая проверка (например, из базы данных)
const whitelist = ['https://site1.com', 'https://site2.com'];
app.use(cors({
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
}
}));
4.3. methods — разрешенные HTTP-методы
Сигнатура: methods: string | string[]
Что делает: Определяет, какие HTTP-методы (GET, POST, PUT, DELETE, PATCH и т.д.) разрешены для кросс-доменных запросов. По умолчанию: GET, HEAD, PUT, PATCH, POST, DELETE.
// Разрешаем только GET и POST
app.use(cors({ methods: ['GET', 'POST'] }));
// Строковый формат
app.use(cors({ methods: 'GET,POST,PUT' }));
4.4. allowedHeaders — разрешенные заголовки
Сигнатура: allowedHeaders: string | string[]
Что делает: Определяет, какие HTTP-заголовки могут быть отправлены в запросе (например, Content-Type, Authorization). По умолчанию разрешены стандартные заголовки.
// Разрешаем кастомные заголовки
app.use(cors({
allowedHeaders: ['Content-Type', 'Authorization', 'X-Custom-Header']
}));
4.5. exposedHeaders — заголовки, доступные клиенту
Сигнатура: exposedHeaders: string | string[]
Что делает: Определяет, какие заголовки ответа могут быть прочитаны клиентским JavaScript-кодом (через response.headers). По умолчанию доступны только стандартные заголовки.
// Делаем заголовок X-Total-Count доступным для клиента
app.use(cors({
exposedHeaders: ['X-Total-Count', 'Content-Range']
}));
4.6. credentials — поддержка кук и авторизации
Сигнатура: credentials: boolean
Что делает: Если установлено в true, сервер разрешает отправку кук, HTTP-аутентификации и TLS-сертификатов клиента. Важно: При credentials: true опция origin не может быть '*', нужно указать конкретный домен.
// Разрешаем куки с конкретного домена
app.use(cors({
origin: 'https://myfrontend.com',
credentials: true
}));
4.7. maxAge — кэширование предварительных запросов
Сигнатура: maxAge: number
Что делает: Указывает браузеру, сколько секунд (время кэширования) можно не отправлять предварительный запрос (preflight) для данного URL. Уменьшает количество запросов к серверу.
// Кэшируем preflight на 24 часа (86400 секунд)
app.use(cors({
maxAge: 86400
}));
4.8. optionsSuccessStatus — статус для preflight-запросов
Сигнатура: optionsSuccessStatus: number
Что делает: Определяет HTTP-статус, который возвращается на предварительные запросы (метод OPTIONS). По умолчанию — 204 (No Content). Некоторые старые браузеры или прокси могут требовать 200.
// Используем статус 200 для совместимости
app.use(cors({
optionsSuccessStatus: 200
}));
5. Реальный практический пример (100-200 строк кода)
Создадим полноценный REST API для управления списком задач (To-Do list) с гибкой настройкой CORS. API будет поддерживать аутентификацию через JWT и разрешать доступ только определенным доменам.
const express = require('express');
const cors = require('cors');
const jwt = require('jsonwebtoken'); // Для примера аутентификации
const app = express();
const PORT = 3000;
const SECRET_KEY = 'your-secret-key-change-in-production';
// --- Настройка CORS ---
const corsOptions = {
// Разрешаем только наш фронтенд и локальную разработку
origin: function (origin, callback) {
const allowedOrigins = [
'https://my-todo-app.com',
'http://localhost:3001', // Для разработки
'http://127.0.0.1:5500' // Для Live Server
];
// Разрешаем запросы без origin (например, из Postman или серверных скриптов)
if (!origin || allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('Доступ запрещен политикой CORS'));
}
},
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Total-Count'],
credentials: true, // Разрешаем куки и JWT в заголовках
maxAge: 3600 // Кэшируем preflight на 1 час
};
app.use(cors(corsOptions));
// --- Middleware для парсинга JSON ---
app.use(express.json());
// --- Хранилище задач (в реальном проекте — база данных) ---
let tasks = [
{ id: 1, title: 'Изучить CORS', completed: false },
{ id: 2, title: 'Написать документацию', completed: true }
];
let nextId = 3;
// --- Middleware для проверки JWT (упрощенный) ---
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (token == null) return res.sendStatus(401);
jwt.verify(token, SECRET_KEY, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
}
// --- Маршруты API ---
// Получить все задачи (публичный endpoint)
app.get('/api/tasks', (req, res) => {
res.setHeader('X-Total-Count', tasks.length);
res.json(tasks);
});
// Получить задачу по ID
app.get('/api/tasks/:id', (req, res) => {
const task = tasks.find(t => t.id === parseInt(req.params.id));
if (!task) return res.status(404).json({ error: 'Задача не найдена' });
res.json(task);
});
// Создать новую задачу (требует аутентификации)
app.post('/api/tasks', authenticateToken, (req, res) => {
const { title } = req.body;
if (!title) return res.status(400).json({ error: 'Название задачи обязательно' });
const newTask = {
id: nextId++,
title: title,
completed: false,
userId: req.user.id // Из JWT
};
tasks.push(newTask);
res.status(201).json(newTask);
});
// Обновить задачу
app.put('/api/tasks/:id', authenticateToken, (req, res) => {
const task = tasks.find(t => t.id === parseInt(req.params.id));
if (!task) return res.status(404).json({ error: 'Задача не найдена' });
const { title, completed } = req.body;
if (title !== undefined) task.title = title;
if (completed !== undefined) task.completed = completed;
res.json(task);
});
// Удалить задачу
app.delete('/api/tasks/:id', authenticateToken, (req, res) => {
const index = tasks.findIndex(t => t.id === parseInt(req.params.id));
if (index === -1) return res.status(404).json({ error: 'Задача не найдена' });
tasks.splice(index, 1);
res.status(204).send();
});
// --- Обработка ошибок CORS (если origin не разрешен) ---
app.use((err, req, res, next) => {
if (err.message === 'Доступ запрещен политикой CORS') {
res.status(403).json({ error: err.message });
} else {
next(err);
}
});
// --- Запуск сервера ---
app.listen(PORT, () => {
console.log(`Сервер запущен на http://localhost:${PORT}`);
console.log('CORS настроен для: https://my-todo-app.com и localhost:3001');
});
// --- Пример получения JWT (для теста) ---
app.post('/api/login', (req, res) => {
const { username } = req Также в библиотеке
Авторизация и аутентификация в Kotlin: JWT, Spring Security и Ktor
Detekt для Kotlin: полное руководство с примерами
Rate Limiting в Kotlin: библиотеки и реализация
CLI фреймворк для Rust: Clap — мощный и удобный инструмент для создания консольных приложений