Что такое Throttler и как реализовать rate limiting в NestJS?

MiddleNestJS · Backend·Обновлено 24 августа 2026
Коротко
Throttler — это официальный модуль @nestjs/throttler, реализующий rate limiting как Guard: он ограничивает число запросов от клиента за заданное окно времени и отклоняет превышающие лимит запросы с кодом 429.

Что такое rate limiting

Rate limiting (ограничение частоты запросов) — техника защиты API от избыточной нагрузки: брутфорса паролей, спама, парсинга данных ботами, случайных или намеренных всплесков трафика. Сервер отслеживает количество запросов от клиента (по IP, токену, пользователю) за интервал времени и отклоняет запросы сверх лимита с кодом 429 Too Many Requests.

Throttler в NestJS

В NestJS для этого есть официальный пакет @nestjs/throttler. Он реализует rate limiting как Guard, использующий алгоритм "фиксированного окна" (fixed window): для каждого трекера (обычно IP) хранится счётчик запросов и время сброса.

Подключение

import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';

@Module({
  imports: [
    ThrottlerModule.forRoot([
      {
        ttl: 60000, // окно в миллисекундах
        limit: 10,  // максимум запросов за окно
      },
    ]),
  ],
  providers: [
    { provide: APP_GUARD, useClass: ThrottlerGuard },
  ],
})
export class AppModule {}

После этого ThrottlerGuard применяется глобально ко всем маршрутам.

Точечная настройка

Декоратор @Throttle() переопределяет лимиты для конкретного контроллера или метода, @SkipThrottle() отключает проверку. Можно задавать несколько именованных лимитов (например, "short" и "long") для разных сценариев одновременно.

@Throttle({ default: { limit: 3, ttl: 60000 } })
@Post('login')
login() { /* строгий лимит на попытки входа */ }

@SkipThrottle()
@Get('health')
health() { /* без ограничений */ }

Хранилище счётчиков

По умолчанию счётчики хранятся в памяти процесса — это не подходит для нескольких инстансов приложения за балансировщиком, так как каждый инстанс считает отдельно. Для распределённого окружения используют ThrottlerStorageRedisService из @nestjs/throttler-storage-redis, чтобы все инстансы делили общий счётчик.

Кастомизация трекера

По умолчанию клиент идентифицируется по IP (req.ip). Если приложение стоит за прокси (nginx, Cloudflare), нужно включить app.set('trust proxy', 1) и/или переопределить метод getTracker() в наследнике ThrottlerGuard, чтобы учитывать реальный IP из заголовков или идентифицировать по userId для авторизованных пользователей.

@Injectable()
export class UserThrottlerGuard extends ThrottlerGuard {
  protected async getTracker(req: Record<string, any>): Promise<string> {
    return req.user?.id ?? req.ip;
  }
}

Зачем это важно с точки зрения security

Rate limiting — базовый уровень защиты: снижает эффективность брутфорса credential и OTP, защищает от исчерпания ресурсов (CPU, БД, платные сторонние API), ограничивает злоупотребление публичными эндпоинтами. Важно комбинировать его с другими мерами (капча, блокировка аккаунта, WAF), так как throttling по IP легко обойти через прокси или ботнет.

Что хочет услышать интервьюер

Понимание, что rate limiting защищает от брутфорса, DoS-подобной нагрузки и злоупотребления API

Знание пакета @nestjs/throttler и того, что он реализован как Guard

Умение настроить ttl/limit глобально и точечно через @Throttle/@SkipThrottle

Понимание проблемы in-memory хранилища при нескольких инстансах и решения через Redis

Знание про кастомизацию трекера (IP за прокси, идентификация по пользователю)

Пример: Базовая настройка ThrottlerModule

import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';

@Module({
  imports: [
    ThrottlerModule.forRoot([
      {
        ttl: 60000,
        limit: 10,
      },
    ]),
  ],
  providers: [
    { provide: APP_GUARD, useClass: ThrottlerGuard },
  ],
})
export class AppModule {}

Пример: Кастомный трекер по userId

@Injectable()
export class UserThrottlerGuard extends ThrottlerGuard {
  protected async getTracker(req: Record<string, any>): Promise<string> {
    return req.user?.id ?? req.ip;
  }
}

Типичные ошибки

Не учитывают, что in-memory throttler считает независимо на каждом инстансе за балансировщиком

Не настраивают trust proxy, из-за чего все запросы считаются с IP самого прокси

Ставят единый общий лимит на все эндпоинты вместо более строгих ограничений для чувствительных маршрутов (login, reset password)

Считают, что throttling полностью защищает от DDoS, хотя он легко обходится через ботнет или ротацию IP

Не обрабатывают код 429 и заголовки X-RateLimit-* на стороне клиента

Лучшие курсы по теме

изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Node.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее