Rate Limiting в Node.js: Полное руководство по защите API и управлению нагрузкой

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Rate Limiting в Node.js: Защита API от перегрузок и злоумышленников

Rate limiting (ограничение скорости запросов) — это критически важный механизм для любого веб-приложения на Node.js. Он позволяет контролировать количество запросов, которые клиент может отправить на сервер за определенный промежуток времени. Без rate limiting ваше API уязвимо для DDoS-атак, случайных перегрузок и чрезмерного потребления ресурсов.

Зачем нужен Rate Limiting?

  • Защита от брутфорса: Предотвращает многократные попытки входа в систему.
  • Предотвращение DDoS: Ограничивает влияние атак на отказ в обслуживании.
  • Справедливое распределение ресурсов: Гарантирует равный доступ для всех пользователей.
  • Экономия затрат: Снижает нагрузку на серверы и базы данных.
  • Соответствие SLA: Выполнение соглашений об уровне обслуживания.

Основные алгоритмы Rate Limiting

Существует несколько подходов к реализации ограничения скорости. Рассмотрим наиболее популярные:

1. Sliding Window (Скользящее окно)

Самый распространенный алгоритм. Запросы группируются во временные окна (например, 1 минута). Если количество запросов превышает лимит, следующие запросы отклоняются до начала нового окна.

2. Token Bucket (Ведро токенов)

Виртуальное "ведро" содержит токены. Каждый запрос потребляет один токен. Токены пополняются с фиксированной скоростью. Если ведро пусто, запрос отклоняется.

3. Leaky Bucket (Дырявое ведро)

Запросы поступают в очередь и обрабатываются с постоянной скоростью. Если очередь переполняется, запросы отбрасываются.

Библиотеки для Rate Limiting в Node.js

1. express-rate-limit

Самая популярная библиотека для Express.js. Простая в использовании и настраиваемая.

const rateLimit = require('express-rate-limit');

// Создаем middleware для ограничения запросов
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 минут
  max: 100, // максимум 100 запросов за окно
  message: 'Слишком много запросов, попробуйте позже.',
  standardHeaders: true, // Возвращает RateLimit-* заголовки
  legacyHeaders: false, // Отключает X-RateLimit-* заголовки
});

// Применяем ко всем маршрутам
app.use(limiter);

// Или только к конкретному маршруту
app.use('/api/login', limiter);

2. bottleneck

Универсальная библиотека, работающая с любыми асинхронными операциями. Поддерживает алгоритмы Token Bucket и Leaky Bucket.

const Bottleneck = require('bottleneck');

// Создаем лимитер: 5 запросов в секунду
const limiter = new Bottleneck({
  minTime: 200, // 200 мс между запросами
  maxConcurrent: 5, // максимум 5 одновременных запросов
  reservoir: 100, // начальное количество токенов
  reservoirRefreshAmount: 100,
  reservoirRefreshInterval: 60 * 1000, // пополнение раз в минуту
});

// Оборачиваем функцию в лимитер
async function fetchData(url) {
  const response = await fetch(url);
  return response.json();
}

const limitedFetch = limiter.wrap(fetchData);

// Использование
const data = await limitedFetch('https://api.example.com/data');

3. rate-limiter-flexible

Гибкая библиотека с поддержкой Redis, MongoDB, Memcached и других хранилищ. Идеальна для распределенных систем.

const { RateLimiterRedis } = require('rate-limiter-flexible');
const Redis = require('ioredis');

const redisClient = new Redis();

const rateLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  keyPrefix: 'middleware',
  points: 10, // 10 запросов
  duration: 1, // за 1 секунду
});

app.use(async (req, res, next) => {
  try {
    await rateLimiter.consume(req.ip);
    next();
  } catch (rejRes) {
    res.status(429).send('Слишком много запросов');
  }
});

Практические примеры

Пример 1: Rate Limiting для API ключей

Ограничиваем запросы для каждого API ключа отдельно:

const rateLimit = require('express-rate-limit');

const apiKeyLimiter = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 час
  max: 1000,
  keyGenerator: (req) => req.headers['x-api-key'] || req.ip,
  handler: (req, res) => {
    res.status(429).json({
      error: 'Превышен лими                    

Рекомендаций