Générez du code de rate limiting pour Node.js, Python et Go
Lissage du trafic avec remplissage progressif de jetons
1import { Redis } from "ioredis";23const redis = new Redis();45interface TokenBucketResult {6 allowed: boolean;7 remaining: number;8 retryAfter: number | null;9}1011/**12 * Token Bucket Rate Limiter13 * Max: 100 requêtes par 1min14 */15export async function tokenBucket(key: string): Promise<TokenBucketResult> {16 const bucketKey = `rate-limit:${key}`;17 const maxTokens = 100;18 const refillRate = maxTokens / (60000 / 1000); // tokens per second19 const now = Date.now();2021 const lua = `22 local key = KEYS[1]23 local maxTokens = tonumber(ARGV[1])24 local refillRate = tonumber(ARGV[2])25 local now = tonumber(ARGV[3])2627 local bucket = redis.call('HMGET', key, 'tokens', 'lastRefill')28 local tokens = tonumber(bucket[1]) or maxTokens29 local lastRefill = tonumber(bucket[2]) or now3031 local elapsed = (now - lastRefill) / 100032 tokens = math.min(maxTokens, tokens + elapsed * refillRate)3334 if tokens >= 1 then35 tokens = tokens - 136 redis.call('HMSET', key, 'tokens', tokens, 'lastRefill', now)37 redis.call('PEXPIRE', key, 60000)38 return {1, math.floor(tokens)}39 else40 redis.call('HMSET', key, 'tokens', tokens, 'lastRefill', now)41 redis.call('PEXPIRE', key, 60000)42 local waitTime = math.ceil((1 - tokens) / refillRate * 1000)43 return {0, waitTime}44 end45 `;4647 const result = await redis.eval(lua, 1, bucketKey, maxTokens, refillRate, now) as number[];4849 if (result[0] === 1) {50 return { allowed: true, remaining: result[1], retryAfter: null };51 }52 return { allowed: false, remaining: 0, retryAfter: result[1] };53}5455// Middleware Express56import { Request, Response, NextFunction } from "express";5758export function rateLimitMiddleware() {59 return async (req: Request, res: Response, next: NextFunction) => {60 const clientKey = req.ip || "unknown";61 const result = await tokenBucket(clientKey);6263 res.setHeader("X-RateLimit-Limit", 100);64 res.setHeader("X-RateLimit-Remaining", result.remaining);6566 if (!result.allowed) {67 res.setHeader("Retry-After", Math.ceil((result.retryAfter || 1000) / 1000));68 return res.status(429).json({ error: "Too Many Requests" });69 }7071 next();72 };73}