Реалізація Rate Limiting для API веб-застосунку

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

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація Rate Limiting для API веб-застосунку
Середня
від 1 робочого дня до 3 робочих днів
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

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 дня.