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);
解决方案
核心问题分析
- 按钮交互无法读取
commandName:按钮交互不属于命令交互,interaction.commandName属性不存在,导致后续判断逻辑完全不执行,交互超时后显示失败。 - 逻辑错误:按钮点击时重新随机取问题:当前代码在按钮点击时重新获取随机问题,与用户正在回答的问题完全不匹配,无法正确判断对错。
- 冗余事件监听:分开的
interactionCreate监听可能导致逻辑冲突,建议合并处理。
修改步骤
- 合并
interactionCreate事件监听,统一处理命令和按钮交互。 - 添加临时缓存存储用户当前的测验问题,确保按钮点击时能匹配到对应的问题答案。
- 修正按钮交互逻辑,基于用户当前的问题判断答案对错,移除无效的
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);
额外说明
- 使用
activeQuizzesMap存储用户当前的测验问题,确保按钮点击时能准确匹配到对应的答案。 - 按钮交互处理时,先验证用户是否有正在进行的测验,避免无效交互。
- 合并事件监听后,逻辑更清晰,避免冲突。
内容的提问来源于stack exchange,提问作者David Wang
相关产品推荐
相关产品推荐

