You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js 如何为Button按钮添加冷却机制避免触发速率限制

Discord.js Button 交互冷却机制实现方案

以下是两种生产可用的实现方案,可直接解决恶意点击按钮导致的bot触发Discord速率限制问题:

方案1:内存级冷却(适合中小型单实例bot)

基于Discord.js内置的Collection实现,自带过期自动清理能力,无需额外依赖:

  1. 初始化冷却存储,在bot启动时挂载全局冷却集合
  2. 在interactionCreate事件中对Button交互做前置校验,通过用户ID+按钮customId生成唯一冷却标识,判断两次点击的时间差是否小于设置的冷却阈值
  3. 冷却期内的点击直接返回仅用户可见的提示,不执行业务逻辑

完整示例代码:

const { Client, GatewayIntentBits, Collection } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });

// 全局默认冷却时长,单位毫秒,可根据不同按钮自定义
const DEFAULT_COOLDOWN = 3000;
// 初始化冷却存储集合
client.buttonCooldowns = new Collection();

client.on('interactionCreate', async interaction => {
  // 只处理按钮交互
  if (!interaction.isButton()) return;

  const cooldownKey = `${interaction.user.id}-${interaction.customId}`;
  const lastClickTime = client.buttonCooldowns.get(cooldownKey);

  // 校验是否处于冷却期
  if (lastClickTime && Date.now() - lastClickTime < DEFAULT_COOLDOWN) {
    const waitTime = Math.ceil((DEFAULT_COOLDOWN - (Date.now() - lastClickTime)) / 1000);
    return interaction.reply({
      content: `操作太频繁,请${waitTime}秒后再试`,
      ephemeral: true
    });
  }

  // 写入冷却记录,到期自动删除释放内存
  client.buttonCooldowns.set(cooldownKey, Date.now(), DEFAULT_COOLDOWN);

  // 此处写入正常按钮业务逻辑
  // ...
});

方案2:持久化冷却(适合集群/多实例bot,重启保留冷却)

如果你的bot使用多实例集群部署,或者希望重启后冷却规则仍然生效,可以使用Redis实现冷却,Redis自带原子操作和TTL过期能力,不会出现竞态问题:

const { Client, GatewayIntentBits } = require('discord.js');
const Redis = require('ioredis');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
const redis = new Redis(); // 自行配置Redis连接参数

const DEFAULT_COOLDOWN = 3000;

client.on('interactionCreate', async interaction => {
  if (!interaction.isButton()) return;

  const cooldownKey = `btn_cooldown:${interaction.user.id}:${interaction.customId}`;
  const isInCooldown = await redis.get(cooldownKey);

  if (isInCooldown) {
    return interaction.reply({
      content: "操作太频繁,请稍后再试",
      ephemeral: true
    });
  }

  // NX参数保证只有key不存在时才写入,避免并发点击的竞态问题
  await redis.set(cooldownKey, 1, 'PX', DEFAULT_COOLDOWN, 'NX');

  // 此处写入正常按钮业务逻辑
  // ...
});

优化建议

  • 冷却提示统一使用*ephemeral(仅用户可见)*属性,不会占用公开频道消息配额,也不会额外触发消息发送的速率限制
  • 可根据按钮的业务属性自定义冷却时长,比如敏感操作(删除配置、触发额度消耗操作)可设置10秒以上冷却,普通查询类操作设置1-2秒即可
  • 若有需要可单独配置全局黑名单,对频繁触发冷却的用户做临时全局限制,进一步降低风险

内容的提问来源于stack exchange,提问作者user16752914

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 18:06:03