如何为Telegram Bot实现Antispam throttler 高频操作临时冻结功能
Telegram Bot 反垃圾限速功能实现方案
核心逻辑
- 以用户ID(
msg.from.id,群聊场景不要用chatId,避免误封整个群)为唯一标识统计请求频次 - 内置两类状态存储:请求时间窗口记录、临时封禁名单
- 所有用户交互事件(消息发送、按钮点击回调)都先经过限速校验,校验不通过直接拦截并返回提示
具体实现
默认配置为10秒内最多触发5次交互,超出后封禁10分钟,可根据实际需求调整参数
小流量场景直接用内存存储即可,高并发生产环境可替换为Redis实现数据持久化、多实例共享。
完整代码示例
import { bot } from '../token.js'; import { keyboardMain } from '../keyboards/keyboardsMain.js'; // 限速配置 const THROTTLE_CONFIG = { TIME_WINDOW: 10 * 1000, // 统计时间窗口:10秒 MAX_REQUESTS: 5, // 时间窗口内最大允许请求数 BAN_DURATION: 10 * 60 * 1000 // 封禁时长:10分钟 } // 内存存储,Bot重启后数据会清空,高并发场景可替换为Redis const userRequestRecords = new Map() // key: 用户ID, value: 时间戳数组 const bannedUsers = new Map() // key: 用户ID, value: 封禁到期时间戳 // 限速校验函数,返回true表示当前用户被限速/封禁 function checkThrottle(userId) { // 先检查是否已在封禁名单内 const banExpireTime = bannedUsers.get(userId) if (banExpireTime) { if (Date.now() < banExpireTime) { return true } // 封禁到期自动移除 bannedUsers.delete(userId) } // 统计当前时间窗口内的有效请求数 const now = Date.now() const userRequests = userRequestRecords.get(userId) || [] // 过滤超出时间窗口的历史请求 const validRequests = userRequests.filter(timestamp => now - timestamp < THROTTLE_CONFIG.TIME_WINDOW) if (validRequests.length >= THROTTLE_CONFIG.MAX_REQUESTS) { // 超出阈值,加入封禁名单 bannedUsers.set(userId, now + THROTTLE_CONFIG.BAN_DURATION) userRequestRecords.delete(userId) return true } // 更新请求记录 validRequests.push(now) userRequestRecords.set(userId, validRequests) return false } export function commands() { // 处理普通消息事件 bot.on('message', msg => { const userId = msg.from.id const chatId = msg.chat.id // 优先做限速校验 if (checkThrottle(userId)) { const remainTime = Math.ceil((bannedUsers.get(userId) - Date.now()) / 60 / 1000) return bot.sendMessage(chatId, `操作过于频繁,请${remainTime}分钟后再尝试`) } const text = msg.text; if (text === '/start') { return bot.sendMessage(chatId, 'hello', keyboardMain); } return bot.sendMessage(chatId, 'error'); }); // 处理按钮点击回调事件,覆盖按钮点击的限速场景 bot.on('callback_query', callback => { const userId = callback.from.id const chatId = callback.message.chat.id if (checkThrottle(userId)) { const remainTime = Math.ceil((bannedUsers.get(userId) - Date.now()) / 60 / 1000) // 回答回调查询避免按钮一直处于加载状态,show_alert控制是否弹出提示框 return bot.answerCallbackQuery(callback.id, { text: `操作过于频繁,请${remainTime}分钟后再尝试`, show_alert: true }) } // 此处填写原有按钮点击处理逻辑 }) }
可选优化点
- 可针对不同交互类型设置差异化阈值,比如普通命令阈值更高,敏感操作阈值更低
- 可新增永久封禁名单,针对恶意用户直接永久拦截
- 存储层替换为Redis后,可支持多Bot实例共享限速、封禁数据,避免分布式部署时规则失效
内容的提问来源于stack exchange,提问作者bandera
相关产品推荐
相关产品推荐

