
在使用discord.js构建机器人时,开发者经常会遇到一个场景:机器人需要定期(例如每隔几秒)向特定频道发送自动化消息,例如新闻更新或状态报告。尽管机器人能够响应用户发起的命令并发送消息,但当尝试通过定时任务(如cron.schedule或setinterval)自动发送消息时,却可能发现消息无法正常发送。这通常不是权限或频道id错误,而是与discord.js的内部缓存机制有关。
Discord.js为了提高性能,会将它最近交互过的服务器(Guild)和频道(Channel)数据缓存起来。当用户发送消息或机器人响应命令时,相关的服务器和频道信息会被加载到缓存中。然而,当机器人执行一个非事件触发的定时任务时,它可能并没有与目标服务器或频道进行过近期交互,导致这些实体不在机器人的缓存中。
在这种情况下,如果代码尝试使用bot.guilds.cache.get(guildId)或guild.channels.cache.find(...)来获取服务器或频道,它们很可能会返回undefined,因为所需的数据未被缓存。即使服务器和频道确实存在且机器人拥有发送消息的权限,这种缓存缺失也会导致查找失败,进而阻止消息的发送。
为了解决这个问题,我们需要确保在定时任务中获取服务器和频道信息时,即使它们不在缓存中,也能直接从Discord API获取最新数据。Discord.js提供了fetch方法来实现这一点。
通过使用fetch方法,我们可以绕过缓存可能导致的查找失败,确保在执行定时任务时始终能够访问到正确的服务器和频道对象。
以下是一个修正后的sendPromptNews函数示例,它演示了如何使用fetch来确保自动消息的可靠发送。
const axios = require('axios');
const cheerio = require('cheerio');
const { Client, GatewayIntentBits } = require('discord.js');
const cron = require('node-cron');
// ... (其他初始化代码,例如bot客户端、express服务器、fetchData函数等) ...
const bot = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});
let targetGuildId = null; // 存储需要发送自动更新的服务器ID
const NEWS_CHANNEL_ID = '1111638079103574159'; // 目标新闻频道ID
const BASE_URL = 'URL I can not mention because of privacy agreement'; // 基础URL
// 假设 fetchData 和 promptNews 数组已定义并正常工作
let promptNews = []; // 假设这里有新闻数据
// 模拟 fetchData 函数,实际应从网站抓取
const fetchData = async () => {
console.log('Fetching news data...');
// 实际中会使用axios和cheerio抓取数据
promptNews = [
{ title: '最新新闻标题 1', link: '/news/1' },
{ title: '最新新闻标题 2', link: '/news/2' },
];
};
// 机器人就绪事件
bot.on('ready', () => {
console.log(`Logged in as ${bot.user.tag}`);
fetchData(); // 机器人启动时立即抓取一次数据
});
// 消息创建事件,用于设置 targetGuildId 和处理用户命令
bot.on('messageCreate', async (message) => {
if (message.author.bot) return; // 忽略机器人自身的消息
if (message.content.toLowerCase() === 'news' && !targetGuildId) {
targetGuildId = message.guildId;
message.reply({ content: '此服务器将接收自动新闻更新。' });
} else if (message.content.toLowerCase() === 'stop news' && message.guildId === targetGuildId) {
targetGuildId = null;
message.reply({ content: '此服务器的自动新闻更新已停止。' });
} else if (message.content.toLowerCase() === 'news' && message.guildId === targetGuildId) {
// 假设这里可以触发一次手动新闻发送
try {
// 实际中这里可以调用 sendPromptNews 或类似函数
const newsData = promptNews.map((item) => `${item.title}\n${BASE_URL}${item.link}`);
newsData.forEach((data) => {
message.reply({ content: `最新新闻摘要:\n\n${data}` });
});
} catch (error) {
console.error('手动获取新闻时发生错误:', error);
message.reply('获取新闻摘要时发生错误。');
}
}
});
/**
* 发送自动新闻更新到指定频道。
* 使用 fetch 确保获取最新的服务器和频道信息。
*/
const sendPromptNews = async () => {
if (targetGuildId) {
try {
// 1. 使用 bot.guilds.fetch 获取服务器,确保数据最新
const guild = await bot.guilds.fetch(targetGuildId);
if (!guild) {
console.error(`错误:未找到ID为 ${targetGuildId} 的服务器。`);
return;
}
// 2. 使用 guild.channels.fetch 获取所有频道,确保数据最新
const channels = await guild.channels.fetch();
// 查找目标新闻频道
const channel = channels.find(
(ch) => ch.type === GatewayIntentBits.GuildMessages && ch.id === NEWS_CHANNEL_ID
);
if (!channel) {
console.error(`错误:在服务器 ${guild.name} 中未找到ID为 ${NEWS_CHANNEL_ID} 的文本频道。`);
return;
}
// 3. 抓取最新新闻数据(或从已缓存的 promptNews 中获取)
// 实际应用中,这里可以再次调用 fetchData() 或从外部API获取
await fetchData(); // 确保 promptNews 是最新的
if (promptNews.length === 0) {
console.log('没有新的新闻可供发送。');
return;
}
// 4. 格式化并发送新闻
const newsData = promptNews.map((item) => `${item.title}\n${BASE_URL}${item.link}`);
for (const data of newsData) {
await channel.send(`突发自动新闻:\n\n${data}`);
}
console.log(`成功发送 ${newsData.length} 条新闻到频道 ${channel.name}。`);
} catch (error) {
console.error('发送自动新闻时发生错误:', error);
// 如果发生错误,尝试通知目标频道 (如果频道对象已获取)
const guild = bot.guilds.cache.get(targetGuildId);
if (guild) {
const channel = guild.channels.cache.get(NEWS_CHANNEL_ID);
if (channel) {
channel.send('获取或发送新闻更新时发生错误。');
}
}
}
} else {
console.log('未设置目标服务器ID,跳过自动新闻发送。');
}
};
// 使用 cron.schedule 安排每10秒发送一次新闻
cron.schedule('*/10 * * * * *', () => {
console.log('触发自动新闻发送任务...');
sendPromptNews();
});
// 机器人登录
bot.login('YOUR_BOT_TOKEN'); // 替换为你的机器人Token当Discord.js机器人在定时任务中无法发送自动消息时,最常见的原因是服务器或频道数据不在机器人的缓存中。通过将cache.get和cache.find替换为fetch方法,我们可以强制机器人从Discord API获取最新的数据,从而解决这个问题。同时,加入详细的错误处理和日志记录是构建健壮机器人的关键,有助于快速定位和解决潜在问题。遵循这些最佳实践,您的Discord机器人将能够更稳定可靠地执行自动化任务。
以上就是Discord.js 机器人自动消息发送与缓存管理教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号