Реализация Rate Limiting для API веб-приложения

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация Rate Limiting для API веб-приложения
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Rate Limiting для API веб-приложения

Rate limiting ограничивает количество запросов от одного источника за единицу времени. Защищает от brute force, credential stuffing, DDoS на уровне приложения и неконтролируемого потребления ресурсов партнёрскими интеграциями. Без rate limiting один клиент с багом (бесконечный retry-loop) может положить всё приложение.

Алгоритмы

Fixed Window — счётчик сбрасывается каждые N секунд. Прост в реализации, но уязвим к burst в момент сброса: 100 запросов в конце окна + 100 в начале следующего = 200 за секунду.

Sliding Window — усреднение по скользящему окну. Ровнее распределяет нагрузку.

Token Bucket — накапливает «токены» со скоростью refill rate, каждый запрос тратит один токен. Позволяет burst до bucket size, потом ограничение.

Leaky Bucket — очередь запросов с фиксированным drain rate. Максимально ровная нагрузка.

Для большинства веб-приложений достаточен Sliding Window с Redis.

Реализация в Laravel

Laravel Throttle middleware из коробки использует cache (Redis):

// routes/api.php
Route::middleware(['auth:sanctum', 'throttle:api'])->group(function () {
    Route::apiResource('articles', ArticleController::class);
});

// config/cache.php — лимиты через RateLimiter
// app/Providers/RouteServiceProvider.php
RateLimiter::for('api', function (Request $request) {
    return $request->user()
        ? Limit::perMinute(300)->by($request->user()->id)
        : Limit::perMinute(60)->by($request->ip());
});

// Разные лимиты для разных тарифов
RateLimiter::for('api', function (Request $request) {
    $user = $request->user();
    if (!$user) return Limit::perMinute(30)->by($request->ip());

    return match($user->plan) {
        'enterprise' => Limit::perMinute(1000)->by($user->id),
        'pro'        => Limit::perMinute(300)->by($user->id),
        default      => Limit::perMinute(60)->by($user->id),
    };
});

Laravel автоматически добавляет заголовки X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After.

Реализация в NestJS + Redis

import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
import { ThrottlerStorageRedisService } from 'nestjs-throttler-storage-redis';

// app.module.ts
ThrottlerModule.forRoot({
  throttlers: [
    { name: 'short', ttl: 1000, limit: 10 },   // 10 req/sec
    { name: 'medium', ttl: 60000, limit: 300 }, // 300 req/min
    { name: 'long', ttl: 3600000, limit: 5000 }, // 5000 req/hour
  ],
  storage: new ThrottlerStorageRedisService(redisClient),
}),

// Декоратор на конкретный эндпоинт
@Throttle({ short: { limit: 3, ttl: 60000 } }) // 3 запроса в минуту
@Post('auth/login')
async login(@Body() dto: LoginDto) { ... }

Rate limiting на уровне Nginx

Первая линия защиты до PHP/Node:

# limit_req_zone — определяем зоны
limit_req_zone $binary_remote_addr zone=api_general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api_auth:10m rate=3r/m;

server {
    location /api/ {
        limit_req zone=api_general burst=20 nodelay;
        limit_req_status 429;
        proxy_pass http://backend;
    }

    location /api/auth/ {
        limit_req zone=api_auth burst=5 nodelay;
        limit_req_status 429;
        proxy_pass http://backend;
    }
}

burst=20 nodelay — разрешает всплеск до 20 запросов одновременно без задержки, затем жёсткое ограничение.

Заголовки ответа

Правильные заголовки rate limit — часть контракта API:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1735689600
Retry-After: 47

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Превышен лимит запросов. Повторите через 47 секунд.",
    "retry_after": 47
  }
}

Retry-After — Unix timestamp или секунды. Клиент должен уважать его и не пытаться раньше.

Distributed rate limiting

При нескольких серверах приложения — счётчики нужно хранить централизованно. Redis + Lua-скрипт для атомарного Sliding Window:

-- sliding_window.lua
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])

redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
local count = redis.call('ZCARD', key)

if count < limit then
    redis.call('ZADD', key, now, now .. math.random())
    redis.call('EXPIRE', key, window / 1000)
    return 1
end
return 0

Bypass-стратегии

Не все запросы должны тратить лимит:

  • Внутренние сервисы (IP-whitelist или service token с безлимитным rate)
  • Webhook endpoint (принимает входящие от внешних сервисов — ограничивать нельзя)
  • Health check /health — не ограничивать
RateLimiter::for('api', function (Request $request) {
    if ($request->ip() === config('services.internal_ip')) {
        return Limit::none();
    }
    // ...
});

Сроки

Rate limiting с Redis (Sliding Window, разные лимиты по тарифам, правильные заголовки): 1–2 дня. С Nginx-уровнем, Lua-скриптом для distributed counting, мониторингом 429-ответов в Grafana: 3–4 дня.