使用discord.js实现用户指定频道消息检测功能遇异常求助
解决Discord机器人检测用户24小时未发消息失效的问题
原代码的核心问题
你当前的代码依赖message.channel.messages.cache查找用户消息,但这个缓存只存储机器人启动后该频道接收的新消息,无法获取机器人启动前的历史消息。这会导致两种错误判断:
- 用户在机器人启动前24小时内发过消息,代码会误判为“未发消息”;
- 用户在机器人启动后没发过消息,代码直接进入判断分支,但实际用户可能之前发过消息只是不在缓存里。
另外,把判断符<改成>后逻辑完全反转:原本是判断“消息时间早于24小时前”,改成>后变成“消息时间晚于24小时前”(即最近24小时内发过消息),只要缓存里有用户的消息就会重复触发私信逻辑,若代码监听了全局message事件,甚至会形成循环,导致无限发送。
修复方案:主动获取完整历史消息
要正确检测用户24小时内的消息,必须通过channel.messages.fetch()主动拉取频道历史消息,而非依赖缓存。以下是修正后的代码:
// 替换为你要检测的指定频道ID const TARGET_CHANNEL_ID = '你的频道ID'; async function checkUserRecentMessage(interactionOrMessage) { const targetChannel = interactionOrMessage.guild.channels.cache.get(TARGET_CHANNEL_ID); if (!targetChannel) { console.error('指定频道不存在'); return false; } const twentyFourHoursAgo = Date.now() - 24 * 3600 * 1000; let userHasRecentMessage = false; let lastFetchedMessageId = null; // 分页获取历史消息,直到找到用户消息或超出24小时范围 try { while (true) { const fetchOptions = { limit: 100 }; if (lastFetchedMessageId) fetchOptions.before = lastFetchedMessageId; const messages = await targetChannel.messages.fetch(fetchOptions); if (messages.size === 0) break; // 无更多消息可获取 // 检查当前页是否有用户24小时内发送的消息 const userRecentMessage = messages.find(msg => msg.author.id === interactionOrMessage.author.id && msg.createdTimestamp >= twentyFourHoursAgo ); if (userRecentMessage) { userHasRecentMessage = true; break; } // 当前页最早消息已超出24小时范围,停止查询 const earliestMessage = messages.last(); if (earliestMessage.createdTimestamp < twentyFourHoursAgo) break; lastFetchedMessageId = earliestMessage.id; } } catch (error) { console.error('获取历史消息失败:', error); return false; } return userHasRecentMessage; } // 调用示例(绑定到特定命令或定时任务) async function handleUserReminder(message) { const hasRecentMessage = await checkUserRecentMessage(message); if (!hasRecentMessage) { try { await message.author.send('你在指定频道已经24小时没发消息了,请及时互动!'); console.log('已向用户发送提醒私信'); } catch (error) { console.error('无法发送私信(用户可能关闭了私信权限):', error); } } }
关键注意事项
- 确保机器人拥有
ReadMessageHistory权限,否则无法获取频道历史消息; - 避免在全局
message事件中直接触发检测逻辑,建议绑定到特定命令(如!check)或定时任务,防止循环触发; - 若频道消息量极大,可适当添加延迟(如
await new Promise(resolve => setTimeout(resolve, 1000))),避免触发Discord API速率限制。
内容的提问来源于stack exchange,提问作者TechyGiraffe
相关产品推荐
相关产品推荐

