// rateLimiter.js - 请求频率限制管理 const logger = require('./logger'); class RateLimiter { constructor() { // 存储请求记录 // key: identifier (设备号或IP), value: { lastRequestTime, count } this.requestMap = new Map(); } /** * 检查是否允许请求 * @param {string} identifier - 标识符(设备号、IP 等) * @param {number} intervalMs - 时间间隔(毫秒) * @returns {object} { allowed: boolean, remainingTime: number } */ checkLimit(identifier, intervalMs = 5000) { if (!identifier) { logger.warn('限流检查: 标识符为空'); return { allowed: true, remainingTime: 0 }; } const now = Date.now(); const record = this.requestMap.get(identifier); if (!record) { // 第一次请求,允许 this.requestMap.set(identifier, { lastRequestTime: now, count: 1 }); logger.info(`✅ 限流: 首次请求 ${identifier}`); return { allowed: true, remainingTime: 0 }; } const timeSinceLastRequest = now - record.lastRequestTime; if (timeSinceLastRequest < intervalMs) { // 请求过于频繁 const remainingTime = intervalMs - timeSinceLastRequest; logger.warn(`⏱️ 限流: ${identifier} 请求过于频繁,需等待 ${remainingTime}ms`); return { allowed: false, remainingTime: Math.ceil(remainingTime) }; } // 允许请求,更新记录 this.requestMap.set(identifier, { lastRequestTime: now, count: record.count + 1 }); logger.info(`✅ 限流: ${identifier} 请求已允许 (第 ${record.count + 1} 次)`); return { allowed: true, remainingTime: 0 }; } /** * 获取限流状态 */ getStatus(identifier) { return this.requestMap.get(identifier) || null; } /** * 获取所有限流记录 */ getAllStatus() { const result = {}; for (const [key, value] of this.requestMap.entries()) { result[key] = value; } return result; } /** * 清空特定标识符的限流记录 */ clearIdentifier(identifier) { if (this.requestMap.has(identifier)) { this.requestMap.delete(identifier); logger.info(`🗑️ 已清空限流记录: ${identifier}`); return true; } return false; } /** * 清空所有限流记录 */ clearAll() { const count = this.requestMap.size; this.requestMap.clear(); logger.info(`🗑️ 已清空所有限流记录 (共 ${count} 条)`); } /** * 获取限流统计信息 */ getStats() { return { totalIdentifiers: this.requestMap.size, records: this.getAllStatus() }; } /** * 清理过期的限流记录(可选) * @param {number} maxAgeMs - 最大保留时间(毫秒) */ cleanupExpired(maxAgeMs = 3600000) { // 默认 1 小时 const now = Date.now(); let cleanedCount = 0; for (const [identifier, record] of this.requestMap.entries()) { if (now - record.lastRequestTime > maxAgeMs) { this.requestMap.delete(identifier); cleanedCount++; } } if (cleanedCount > 0) { logger.info(`🧹 已清理过期限流记录: ${cleanedCount} 条`); } return cleanedCount; } } // 导出单例 module.exports = new RateLimiter();