Discord.js如何检测用户是否已在指定频道发送过消息
Discord特定频道重复发消息用户拦截实现
需求说明
需要实现拦截在指定频道重复发送消息的用户功能,当前已有代码完成了角色权限校验、触发私信、DM侧消息收集器逻辑,需要补全收集到用户ok开头消息时的「用户是否已在目标频道发过消息」判断分支,执行对应拦截处理。
现有基础代码
client.on("message", async message => { if ((message.content === config.RUN) && message.member.roles.cache.has(config.ROLE_ID)) { if (message.channel.type === 'DM') return; let filter = m => !m.author.bot; let destination = client.channels.cache.get(config.CHANNEL_ID); message.author.createDM().then(dmchannel => { dmchannel.send(textDM.FIRST_DM); const collector = new discord.MessageCollector(dmchannel, filter); collector.on('collect', (m, col) => { console.log(m.content); if (m.content.startsWith("ok")) { // 此处需要补全:用户已在目标频道发过消息的判断 + 拦截逻辑 } }) }) } })
实现方案
用内存集合存储已在目标频道发过消息的用户ID,启动时初始化历史数据,实时监听新消息更新集合,在收集器分支直接做判断即可,性能比每次拉取频道历史消息高很多。
- 先在事件监听外定义存储集合,加初始化和实时更新逻辑
const discord = require('discord.js'); const client = new discord.Client(); // 存储已在目标频道发过消息的非机器人用户ID const submittedUserSet = new Set(); // bot启动完成后拉取目标频道近期消息初始化集合 client.on('ready', async () => { const targetChannel = client.channels.cache.get(config.CHANNEL_ID); if (!targetChannel) return; // 单接口最多拉100条历史消息,需要更久记录可分批循环拉取 const historyMsgs = await targetChannel.messages.fetch({ limit: 100 }); historyMsgs.forEach(msg => { if (!msg.author.bot) submittedUserSet.add(msg.author.id); }); }); // 实时监听目标频道新消息,同步更新已提交用户集合 client.on('message', msg => { if (msg.channel.id === config.CHANNEL_ID && !msg.author.bot) { submittedUserSet.add(msg.author.id); } });
- 补全消息收集器内的判断分支
collector.on('collect', (m, col) => { console.log(m.content); if (m.content.startsWith("ok")) { // 判断用户是否已提交过 if (submittedUserSet.has(m.author.id)) { // 拦截逻辑:提示重复提交、终止收集器 m.reply("你已在对应频道发送过消息,请勿重复提交"); collector.stop('duplicate_submit'); return; } // 未提交则执行正常业务逻辑,比如转发内容到目标频道 const submitContent = m.content.replace(/^ok\s*/i, ''); destination.send(`${m.author.tag} 提交内容:${submitContent}`); // 提交成功后将用户加入已提交集合 submittedUserSet.add(m.author.id); m.reply("提交成功"); collector.stop('submit_success'); } })
注意事项
- 如果bot重启频率高、需要永久留存提交记录,把内存Set替换成Redis、SQLite这类持久化存储即可,不需要每次启动拉取历史消息
- 所有接口调用(发消息、拉取历史)建议加
catch做异常捕获,避免接口报错导致bot进程崩溃 - 如果需要限制特定周期内的重复提交(比如24小时内不能重复发),可以把Set结构改成Map,value存用户上次发消息的时间戳,判断时校验时间差即可
内容的提问来源于stack exchange,提问作者Crash
相关产品推荐
相关产品推荐

