// 简单的内存速率限制器(基于 IP) interface RateLimitEntry { count: number; resetAt: number; } const store = new Map(); // 定期清理过期条目,防止内存泄漏 const CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 5 分钟 setInterval(() => { const now = Date.now(); for (const [key, entry] of store) { if (now >= entry.resetAt) { store.delete(key); } } }, CLEANUP_INTERVAL_MS); /** * 检查请求是否超过速率限制 * @param key 限制键(通常是 IP 地址) * @param maxAttempts 窗口期内最大尝试次数 * @param windowMs 窗口期(毫秒) * @returns 如果超限返回 true,否则返回 false */ export function isRateLimited( key: string, maxAttempts: number = 5, windowMs: number = 60 * 1000 ): boolean { const now = Date.now(); const entry = store.get(key); if (!entry || now >= entry.resetAt) { store.set(key, { count: 1, resetAt: now + windowMs }); return false; } entry.count += 1; return entry.count > maxAttempts; } /** * 从 Request 对象中提取客户端 IP */ export function getClientIp(req: Request): string { // 常见的代理头 const forwarded = req.headers.get("x-forwarded-for"); if (forwarded) { return forwarded.split(",")[0].trim(); } const realIp = req.headers.get("x-real-ip"); if (realIp) { return realIp.trim(); } return "unknown"; }