Rate Limiting в TypeScript: полное руководство по инструментам и реализации
Rate limiting (ограничение скорости запросов) — одна из ключевых техник защиты веб-приложений и API от злоупотреблений, DDoS-атак и чрезмерной нагрузки. В TypeScript, благодаря строгой типизации и современным возможностям, реализация rate limiting становится особенно элегантной и надёжной. В этой статье мы разберём лучшие библиотеки, алгоритмы и примеры кода для TypeScript.
Зачем нужен Rate Limiting?
Без ограничения скорости запросов ваше приложение может столкнуться с:
- Перегрузкой сервера — один клиент может отправить тысячи запросов в секунду
- Брутфорс-атаками — подбор паролей или токенов
- Финансовыми потерями — если каждый запрос требует платных ресурсов (например, API OpenAI)
- Неравномерным распределением ресурсов — один пользователь может забрать всю пропускную способность
Популярные библиотеки для Rate Limiting в TypeScript
1. bottleneck — универсальный ограничитель
Одна из самых популярных библиотек для rate limiting в JavaScript/TypeScript. Поддерживает как ограничение по количеству запросов в секунду/минуту, так и "hanging" (накопление) запросов в очереди.
import Bottleneck from 'bottleneck';
const limiter = new Bottleneck({
maxConcurrent: 2, // максимум 2 одновременных запроса
minTime: 1000, // минимум 1 секунда между запросами
reservoir: 10, // общий лимит на период
reservoirRefreshAmount: 10,
reservoirRefreshInterval: 60 * 1000 // обновление каждую минуту
});
async function fetchData(url: string): Promise<any> {
return limiter.schedule(() => fetch(url));
}
// Использование
const users = await Promise.all([
fetchData('/api/users/1'),
fetchData('/api/users/2'),
fetchData('/api/users/3'), // этот запрос будет ждать
]);
2. express-rate-limit — для Express.js
Стандартное решение для ограничения запросов в Express-приложениях. Отлично работает с TypeScript.
import express from 'express';
import rateLimit from 'express-rate-limit';
const app = express();
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 минут
max: 100, // максимум 100 запросов
standardHeaders: true, // возвращать заголовки RateLimit-*
legacyHeaders: false,
message: {
status: 429,
message: 'Слишком много запросов, попробуйте позже'
}
});
app.use('/api/', apiLimiter);
app.listen(3000);
3. rate-limiter-flexible — гибкое решение для Redis и встроенной памяти
Библиотека с поддержкой различных хранилищ (Redis, Memory, MongoDB, Postgres) и алгоритмов (Token Bucket, Sliding Window).
import { RateLimiterMemory } from 'rate-limiter-flexible';
const rateLimiter = new RateLimiterMemory({
points: 5, // 5 запросов
duration: 1, // за 1 секунду
});
async function checkRateLimit(key: string): Promise<boolean> {
try {
await rateLimiter.consume(key);
return true; // запрос разрешён
} catch (error) {
return false; // превышен лимит
}
}
// Пример использования в Express
app.post('/api/login', async (req, res) => {
const allowed = await checkRateLimit(req.ip);
if (!allowed) {
return res.status(429).json({ error: 'Too Many Requests' });
}
// обработка логина...
});
Алгоритмы Rate Limiting
- Token Bucket — "ведро" с токенами, которые пополняются с постоянной скоростью. Каждый запрос потребляет один токен. Позволяет кратковременные всплески.
- Sliding Window — скользящее окно времени (например, 1 минута). Учитывает запросы не за фиксированные интервалы, а за последние N секунд. Более точный.
- Fixed Window — фиксированные временные окна (например, каждый час). Простой, но может пропускать "краевые" всплески.
- Leaky Bucket — запросы обрабатываются с постоянной скоростью, избыток отбрасывается или ставится в очередь.
Продвинутый пример: кастомный декоратор для Rate Limiting
В TypeScript можно создать элегантный декоратор для ограничения вызова методов:
function RateLimit(maxRequests: number, windowMs: number) {
const store = new Map<string, { count: number; resetTime: Также в библиотеке
Elasticsearch клиент для C++: elasticlient и полное руководство
Обработка Markdown в C# (.NET): библиотеки и инструменты
PDF генерация в C# (.NET): лучшие библиотеки и примеры кода