TL;DR
Rate Limiting to ograniczanie liczby zapytań do API w określonym czasie. Chroni przed nadużyciami, DDoS i zapewnia sprawiedliwy dostęp do zasobów. Oto jak wdrożyć rate limiting w 2026.
Dla kogo to jest
- Deweloperów budujących publiczne API
- Zespołów potrzebujących ochrony przed nadużyciami
- Firm oferujących API jako produkt
- Projektów wymagających kontroli kosztów
Fraza (SEO)
rate limiting, api rate limit, ddos protection, api security, throttling, express rate limit, redis rate limiting
Czym jest Rate Limiting?
Rate Limiting to:
- Ograniczenie liczby zapytań w czasie
- Ochrona przed nadużyciami i DDoS
- Sprawiedliwy dostęp do zasobów
- Kontrola kosztów infrastruktury
Przykład:
Limit: 100 zapytań na minutę
Użytkownik 1: 50 zapytań ✅
Użytkownik 2: 150 zapytań ❌ (blokada po 100)
Dlaczego Rate Limiting?
1. Ochrona przed nadużyciami
Scenariusze:
- Bot scraping danych
- Brute force attacks
- API abuse
- Nieautoryzowany dostęp
Bez rate limiting:
Atakujący: 10,000 zapytań/sekundę
Serwer: Przeciążony, crash
Z rate limiting:
Atakujący: 10,000 zapytań/sekundę
Rate limiter: Blokuje po 100/min
Serwer: Działa normalnie
2. Kontrola kosztów
Problem:
- Każde zapytanie kosztuje (compute, database)
- Nieograniczone API = nieograniczone koszty
- Trudna kontrola budżetu
Rozwiązanie:
- Limity per użytkownik
- Kontrola zużycia zasobów
- Przewidywalne koszty
3. Sprawiedliwy dostęp
Dla wszystkich użytkowników:
- Jeden użytkownik nie może zmonopolizować API
- Równy dostęp do zasobów
- Lepsze doświadczenie
4. Zapobieganie błędom
Ochrona przed:
- Przypadkowym infinite loop
- Błędami w kodzie klienta
- Niewłaściwym użyciem API
Strategie Rate Limiting
1. Fixed Window
Jak działa:
- Okno czasowe (np. 1 minuta)
- Licznik resetuje się co okno
- Proste w implementacji
Przykład:
Okno: 1 minuta
Limit: 100 zapytań
00:00-00:59: 100 zapytań ✅
01:00-01:59: Reset, nowe 100 zapytań ✅
Problem:
- Burst na granicy okien
- Możliwość 200 zapytań w 2 sekundy (na końcu i początku okna)
2. Sliding Window
Jak działa:
- Okno przesuwające się w czasie
- Liczy zapytania z ostatnich N sekund
- Bardziej sprawiedliwe
Przykład:
Limit: 100 zapytań na 60 sekund
00:00: 50 zapytań (dostępne: 50)
00:30: 30 zapytań (dostępne: 20)
01:00: 20 zapytań (dostępne: 0, blokada)
01:30: Zapytania z 00:30 wygasają (dostępne: 20)
3. Token Bucket
Jak działa:
- Wiadro z tokenami
- Tokeny dodawane w stałym tempie
- Zapytanie zużywa token
- Brak tokenów = blokada
Przykład:
Pojemność: 100 tokenów
Dodawanie: 10 tokenów/sekundę
Zapytanie: 1 token
4. Leaky Bucket
Jak działa:
- Wiadro z dziurą
- Zapytania wchodzą do wiadra
- Stałe tempo wyciekania
- Pełne wiadro = blokada
Implementacja
1. Express.js z express-rate-limit
Instalacja:
npm install express-rate-limit
Podstawowe użycie:
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minut
max: 100, // 100 zapytań na okno
message: 'Too many requests, please try again later.',
standardHeaders: true,
legacyHeaders: false,
});
app.use('/api/', limiter);
Różne limity dla różnych endpointów:
// Ogólny limit
const generalLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
});
// Stricter limit dla auth
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // Tylko 5 prób logowania
skipSuccessfulRequests: true,
});
app.use('/api/', generalLimiter);
app.use('/api/auth/login', authLimiter);
Z Redis (dla wielu instancji):
npm install express-rate-limit redis
import RedisStore from 'rate-limit-redis';
import { createClient } from 'redis';
const redisClient = createClient();
await redisClient.connect();
const limiter = rateLimit({
store: new RedisStore({
client: redisClient,
prefix: 'rl:',
}),
windowMs: 15 * 60 * 1000,
max: 100,
});
2. Next.js API Routes
Middleware approach:
// lib/rateLimit.ts
import { NextRequest, NextResponse } from 'next/server';
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL!,
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});
const ratelimit = new Ratelimit({
redis,
limiter: Ratelimit.slidingWindow(10, '10 s'),
});
export async function rateLimit(request: NextRequest) {
const ip = request.ip ?? '127.0.0.1';
const { success, limit, remaining } = await ratelimit.limit(ip);
if (!success) {
return NextResponse.json(
{ error: 'Too many requests' },
{ status: 429 }
);
}
return { limit, remaining };
}
Użycie w API route:
// app/api/users/route.ts
import { rateLimit } from '@/lib/rateLimit';
export async function GET(request: NextRequest) {
const rateLimitResult = await rateLimit(request);
if (rateLimitResult instanceof NextResponse) {
return rateLimitResult; // Rate limit exceeded
}
// Normalna logika
return NextResponse.json({ users: [] });
}
3. Custom implementation z Redis
Sliding window log:
import { createClient } from 'redis';
const redis = createClient();
await redis.connect();
async function checkRateLimit(
key: string,
limit: number,
windowSeconds: number
): Promise<{ allowed: boolean; remaining: number }> {
const now = Date.now();
const windowStart = now - windowSeconds * 1000;
// Usuń stare zapytania
await redis.zRemRangeByScore(key, 0, windowStart);
// Policz aktualne zapytania
const count = await redis.zCard(key);
if (count >= limit) {
return { allowed: false, remaining: 0 };
}
// Dodaj nowe zapytanie
await redis.zAdd(key, {
score: now,
value: `${now}-${Math.random()}`,
});
// Ustaw TTL
await redis.expire(key, windowSeconds);
return { allowed: true, remaining: limit - count - 1 };
}
// Użycie
const result = await checkRateLimit('user:123', 100, 60);
if (!result.allowed) {
return res.status(429).json({ error: 'Rate limit exceeded' });
}
Best Practices
1. Różne limity dla różnych endpointów
Strategia:
const limits = {
public: { windowMs: 15 * 60 * 1000, max: 100 },
auth: { windowMs: 15 * 60 * 1000, max: 5 },
upload: { windowMs: 60 * 60 * 1000, max: 10 },
search: { windowMs: 60 * 1000, max: 20 },
};
2. Identyfikacja użytkowników
Metody:
- IP address (dla publicznych API)
- API key (dla autoryzowanych)
- User ID (dla zalogowanych)
- Session ID
Przykład:
function getIdentifier(req: Request): string {
// Priorytet: API key > User ID > IP
return (
req.headers.get('x-api-key') ||
req.user?.id ||
req.ip ||
'anonymous'
);
}
3. Headers informacyjne
Standardowe headery:
res.setHeader('X-RateLimit-Limit', '100');
res.setHeader('X-RateLimit-Remaining', '50');
res.setHeader('X-RateLimit-Reset', resetTime);
4. Graceful degradation
Zamiast blokować całkowicie:
if (rateLimitExceeded) {
// Opcja 1: Queue request
await queueRequest(request);
// Opcja 2: Throttle (spowolnij)
await sleep(1000);
// Opcja 3: Return cached data
return getCachedResponse();
}
5. Monitoring i alerty
Śledź:
- Liczbę zablokowanych zapytań
- Top użytkowników/IP
- Wzorce nadużyć
- Performance impact
Rate Limiting vs Throttling
| Rate Limiting | Throttling |
|---|---|
| Blokuje po limicie | Spowalnia zapytania |
| Hard limit | Soft limit |
| 429 status | Opóźnia odpowiedź |
| Dla bezpieczeństwa | Dla wydajności |
FAQ
Jakie limity ustawić?
Zależy od przypadku:
- Publiczne API: 100-1000/min
- Auth endpoints: 5-10/min
- Upload: 10-50/godzinę
- Search: 20-100/min
Co zrobić gdy limit przekroczony?
- Zwróć 429 status
- Dodaj Retry-After header
- Poinformuj użytkownika
- Zaoferuj upgrade planu
Czy rate limiting spowalnia API?
Minimalnie (zwykle <1ms). Warto użyć Redis dla cache i szybkiego sprawdzania.
Jak testować rate limiting?
// Test
for (let i = 0; i < 150; i++) {
const res = await fetch('/api/endpoint');
if (i >= 100) {
expect(res.status).toBe(429);
}
}