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

Discord.js定时发送生日Embed消息失败问题排查

Discord生日祝福Bot无法发送Embed消息的修复方案

核心问题排查

你的代码里有几个关键错误导致Embed发不出去:

  • 错误获取Discord客户端实例:const client = Client; 拿的是类而不是已经初始化的客户端实例,根本无法调用频道相关方法
  • MongoDB查询条件无效:存储的生日是完整的DD.MM.YYYY格式,但查询用${day}.${month}.直接匹配,找不到任何数据
  • 定时器逻辑位置错误:把setInterval放在slash命令的execute方法里,每次用户执行命令都会新增一个定时器,导致重复触发甚至资源浪费
  • 频道获取依赖缓存:只用channels.cache.get()可能因为频道没在缓存中导致获取失败

修复后的完整代码

1. 生日命令文件(/commands/birthday.js)

const { EmbedBuilder, SlashCommandBuilder } = require('discord.js');
const Birthday = require('../../Models/Birthday');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('birthday')
    .setDescription('保存用户生日')
    .addUserOption(option =>
      option.setName('user')
        .setDescription('选择用户')
        .setRequired(true))
    .addStringOption(option =>
      option.setName('date')
        .setDescription('输入生日(格式:DD.MM.YYYY)')
        .setRequired(true)),

  async execute(interaction) {
    const user = interaction.options.getUser('user');
    const date = interaction.options.getString('date');

    // 简单校验日期格式(可选,增强鲁棒性)
    const dateRegex = /^\d{2}\.\d{2}\.\d{4}$/;
    if (!dateRegex.test(date)) {
      return interaction.reply({ content: '请输入正确的日期格式:DD.MM.YYYY', ephemeral: true });
    }

    // 检查是否已存在该用户的生日记录,避免重复存储
    const existingBirthday = await Birthday.findOne({ userId: user.id });
    if (existingBirthday) {
      return interaction.reply({ content: `${user.username}的生日已经存在,当前记录是${existingBirthday.birthday}`, ephemeral: true });
    }

    const birthday = new Birthday({
      userId: user.id,
      birthday: date,
    });
    await birthday.save();

    await interaction.reply(`${user.username}的生日已保存为${date}。`);
  }
};

2. 客户端启动文件(比如index.js)

把生日检查的定时器放在客户端启动完成后,避免重复创建:

const { Client, GatewayIntentBits } = require('discord.js');
const Birthday = require('./Models/Birthday');
require('dotenv').config();

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent
  ]
});

client.on('ready', async () => {
  console.log(`已登录为 ${client.user.tag}`);
  
  // 每隔1小时检查一次生日(建议不要太频繁,比如1小时一次)
  setInterval(async () => {
    const today = new Date();
    const month = String(today.getMonth() + 1).padStart(2, '0'); // 补零确保两位,比如1月变成01
    const day = String(today.getDate()).padStart(2, '0');

    // 查询生日匹配今日日/月的用户(忽略年份)
    const users = await Birthday.find({
      birthday: { $regex: `^${day}\\.${month}\\.` }
    });

    if (users.length === 0) return;

    // 获取目标频道,用fetch确保能拿到,不管缓存
    const channelId = '1034193578450231346';
    let channel;
    try {
      channel = await client.channels.fetch(channelId);
    } catch (err) {
      console.error('无法获取目标频道:', err);
      return;
    }

    for (const birthdayDoc of users) {
      // 获取用户对象,显示用户名
      const user = await client.users.fetch(birthdayDoc.userId).catch(err => null);
      const userName = user ? user.username : `用户ID: ${birthdayDoc.userId}`;

      const embed = new EmbedBuilder()
        .setColor('#0099ff')
        .setTitle(`生日快乐 ${userName}! 🎉`)
        .setDescription(`今天是你的生日,祝你度过超棒的一天!`)
        .setTimestamp()
        .setFooter({ text: '生日祝福Bot' });

      // 发送提及+Embed
      await channel.send({
        content: user ? `<@${user.id}>` : `@${userName}`,
        embeds: [embed]
      });
    }
  }, 1000 * 60 * 60); // 1小时间隔,可根据需求调整
});

client.login(process.env.DISCORD_TOKEN);

关键修复说明

  1. 客户端实例获取:直接使用初始化后的client实例,而不是Client类,确保能正常调用Discord API
  2. MongoDB查询优化:用正则表达式$regex匹配生日的前5位(DD.MM.),正确筛选出今日过生日的用户
  3. 定时器位置调整:将检查逻辑放在客户端ready事件中,确保只创建一个定时器,避免重复触发
  4. 频道获取优化:使用channels.fetch()替代cache.get(),即使频道不在缓存中也能获取到
  5. 用户信息优化:通过users.fetch()获取用户对象,在Embed中显示用户名而非冰冷的ID,提升体验
  6. 日期格式补零:用padStart(2, '0')确保月份和日期都是两位,避免1月写成1导致匹配失败(比如存储的是01.05.2000,查询用1.5.就匹配不到)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 11:53:16