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

Discord.js V13语言测验机器人按钮交互失败问题求助

问题

开发基于Discord.js V13的语言测验机器人时,点击消息按钮后显示“this interaction failed”,控制台无任何报错信息,预期点击按钮后机器人能反馈答案正确或错误。代码如下:

const { Client, Intents, MessageActionRow, MessageButton } = require('discord.js');
const { REST } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const { SlashCommandBuilder } = require('@discordjs/builders');
const mySecret = process.env['Key'];
const clientID = process.env.CLIIENT_ID;
const guildID = process.env.GUILD_ID;

const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] });

const commands = [
  {
    name: 'learngerman',
    description: 'Learn German',
  },
  {
    name: 'learnrussian',
    description: 'Learn Russian',
  },
];

const rest = new REST({ version: '9' }).setToken(mySecret);

(async () => {
  try {
    console.log('Started refreshing application (/) commands.');

    await rest.put(
      Routes.applicationGuildCommands(clientID, guildID),
      { body: commands },
    );

    console.log('Successfully reloaded application (/) commands.');
  } catch (error) {
    console.error('Error refreshing application (/) commands:', error);
  }
})();

const questions = {
  german: [
    { question: 'Translate the word "dog" to German:', answer: 'Hund', choices: ['Hund', 'Katze', 'Auto', 'Tisch'] },
    { question: 'Translate the word "tree" to German:', answer: 'Baum', choices: ['Baum', 'Blume', 'Haus', 'Buch'] },
    { question: 'Translate the word "computer" to German:', answer: 'Computer', choices: ['Computer', 'Fenster', 'Stuhl', 'Telefon'] },
    // Add more German questions as needed
  ],
  russian: [
    { question: 'Translate the word "cat" to Russian:', answer: 'кошка', choices: ['кошка', 'собака', 'машина', 'дом'] },
    { question: 'Translate the word "sun" to Russian:', answer: 'солнце', choices: ['солнце', 'луна', 'звезда', 'вода'] },
    { question: 'Translate the word "book" to Russian:', answer: 'книга', choices: ['книга', 'стол', 'цветок', 'окно'] },
    // Add more Russian questions as needed
  ],
};

client.once('ready', () => {
  console.log(`Logged in as ${client.user.tag}!`);
});

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

  const { customId, user } = interaction;
  const choiceIndex = parseInt(customId);

  if (interaction.customId.startsWith('choice_')) {
    // Interaction is from the initial question, ignore it
    return;
  }

  const commandName = interaction.commandName;

  if (commandName === 'learngerman' || commandName === 'learnrussian') {
    // Implement German and Russian learning logic
    const language = commandName === 'learngerman' ? 'german' : 'russian';
    const randomQuestion = questions[language][Math.floor(Math.random() * questions[language].length)];
    const { answer } = randomQuestion;
    const correct = choiceIndex === 0 && interaction.user.id === user.id;

    await interaction.update({
      content: correct ? `Correct! ${user.username} answered "${answer}".` : `Incorrect! The correct answer is "${answer}".`,
      components: [],
    });
  }
});

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

  const { commandName } = interaction;

  if (commandName === 'learngerman' || commandName === 'learnrussian') {
    // Implement German and Russian learning logic
    const language = commandName === 'learngerman' ? 'german' : 'russian';
    const randomQuestion = questions[language][Math.floor(Math.random() * questions[language].length)];
    const { question, choices } = randomQuestion;

    const row = new MessageActionRow()
      .addComponents(
        choices.map((choice, index) => new MessageButton()
          .setCustomId(index.toString())
          .setLabel(choice)
          .setStyle('PRIMARY')),
      );

    await interaction.reply({
      content: `${question}`,
      components: [row],
    });
  }
});

client.login(mySecret);
解决方案

核心问题分析

  1. 按钮交互无法读取commandName:按钮交互不属于命令交互,interaction.commandName属性不存在,导致后续判断逻辑完全不执行,交互超时后显示失败。
  2. 逻辑错误:按钮点击时重新随机取问题:当前代码在按钮点击时重新获取随机问题,与用户正在回答的问题完全不匹配,无法正确判断对错。
  3. 冗余事件监听:分开的interactionCreate监听可能导致逻辑冲突,建议合并处理。

修改步骤

  1. 合并interactionCreate事件监听,统一处理命令和按钮交互。
  2. 添加临时缓存存储用户当前的测验问题,确保按钮点击时能匹配到对应的问题答案。
  3. 修正按钮交互逻辑,基于用户当前的问题判断答案对错,移除无效的commandName判断。

修正后的完整代码

const { Client, Intents, MessageActionRow, MessageButton } = require('discord.js');
const { REST } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const mySecret = process.env['Key'];
const clientID = process.env.CLIIENT_ID;
const guildID = process.env.GUILD_ID;

const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] });

const commands = [
  {
    name: 'learngerman',
    description: '学习德语',
  },
  {
    name: 'learnrussian',
    description: '学习俄语',
  },
];

const rest = new REST({ version: '9' }).setToken(mySecret);

(async () => {
  try {
    console.log('开始刷新应用(/)命令');

    await rest.put(
      Routes.applicationGuildCommands(clientID, guildID),
      { body: commands },
    );

    console.log('成功重载应用(/)命令');
  } catch (error) {
    console.error('刷新应用(/)命令出错:', error);
  }
})();

const questions = {
  german: [
    { question: '将单词"dog"翻译成德语:', answer: 'Hund', choices: ['Hund', 'Katze', 'Auto', 'Tisch'] },
    { question: '将单词"tree"翻译成德语:', answer: 'Baum', choices: ['Baum', 'Blume', 'Haus', 'Buch'] },
    { question: '将单词"computer"翻译成德语:', answer: 'Computer', choices: ['Computer', 'Fenster', 'Stuhl', 'Telefon'] },
    // 可添加更多德语题目
  ],
  russian: [
    { question: '将单词"cat"翻译成俄语:', answer: 'кошка', choices: ['кошка', 'собака', 'машина', 'дом'] },
    { question: '将单词"sun"翻译成俄语:', answer: 'солнце', choices: ['солнце', 'луна', 'звезда', 'вода'] },
    { question: '将单词"book"翻译成俄语:', answer: 'книга', choices: ['книга', 'стол', 'цветок', 'окно'] },
    // 可添加更多俄语题目
  ],
};

// 临时缓存用户当前的测验问题
const activeQuizzes = new Map();

client.once('ready', () => {
  console.log(`已登录为 ${client.user.tag}!`);
});

client.on('interactionCreate', async interaction => {
  // 处理命令交互
  if (interaction.isCommand()) {
    const { commandName } = interaction;

    if (commandName === 'learngerman' || commandName === 'learnrussian') {
      const language = commandName === 'learngerman' ? 'german' : 'russian';
      const randomQuestion = questions[language][Math.floor(Math.random() * questions[language].length)];
      const { question, choices, answer } = randomQuestion;

      // 缓存用户当前的测验信息
      activeQuizzes.set(interaction.user.id, {
        answer: answer,
        choices: choices
      });

      const row = new MessageActionRow()
        .addComponents(
          choices.map((choice, index) => new MessageButton()
            .setCustomId(index.toString())
            .setLabel(choice)
            .setStyle('PRIMARY')),
        );

      await interaction.reply({
        content: `${question}`,
        components: [row],
      });
    }
    return;
  }

  // 处理按钮交互
  if (interaction.isButton()) {
    const { customId, user } = interaction;
    const choiceIndex = parseInt(customId);

    // 获取用户当前的测验信息
    const userQuiz = activeQuizzes.get(user.id);
    if (!userQuiz) {
      await interaction.reply({ content: '你没有正在进行的测验!', ephemeral: true });
      return;
    }

    const selectedChoice = userQuiz.choices[choiceIndex];
    const correct = selectedChoice === userQuiz.answer;

    // 移除已完成的测验缓存
    activeQuizzes.delete(user.id);

    await interaction.update({
      content: correct ? `正确!${user.username} 回答了"${selectedChoice}"。` : `错误!正确答案是"${userQuiz.answer}"。`,
      components: [],
    });
    return;
  }
});

client.login(mySecret);

额外说明

  • 使用activeQuizzes Map存储用户当前的测验问题,确保按钮点击时能准确匹配到对应的答案。
  • 按钮交互处理时,先验证用户是否有正在进行的测验,避免无效交互。
  • 合并事件监听后,逻辑更清晰,避免冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 00:02:05