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

Discord.js添加按钮后报Interaction已确认API错误排查

报错根因

DiscordAPIError: Interaction has already been acknowledged 本质是同一个Discord交互被重复响应,你怀疑的异步时序问题确实存在,代码里一共4处直接触发这个报错的问题:

  • 条件判断漏写花括号:if (!interaction.isButton()) 后没有包裹代码块,JS默认仅将紧邻的下一行纳入判断范围,后续的接口请求、发消息逻辑在按钮交互触发时也会执行,导致重复响应。
  • 斜杠命令响应超时:Discord规定斜杠交互必须在触发后3秒内返回响应,你当前逻辑是等TMDB接口返回数据后才调用interaction.reply(),接口耗时超过3秒时交互会被Discord自动标记为已处理,再调用reply就会触发报错。
  • 收集器过滤器逻辑错误:i => i.customId === 'red' || 'orange' || 'blue' || 'green' 是无效写法,非空字符串在JS里是真值,这个过滤器会收进频道内所有按钮交互,极易误响应其他交互触发报错。
  • 收集器绑定范围错误:你用interaction.channel.createMessageComponentCollector给整个频道绑定收集器,每触发一次命令就会新增一个收集器,多次触发后多个收集器会同时响应同一个按钮点击,导致重复操作交互。
修复后可直接运行的代码
async execute(interaction) {
    if(!interaction.isCommand()) return;
    // 提前延迟响应,将交互响应窗口延长至15分钟,彻底解决3秒超时问题
    await interaction.deferReply();
    const getChoices = interaction.options.getString('ne_öğrenmek_istersin'); 

    if(getChoices === 'popüler') {
        // 统一用await处理异步,替换then链式调用避免时序混乱
        const res = await moviedb.moviePopular({ language: 'tr'})
        const cizgi = '`'
        const num = Math.floor(Math.random () * 3)

        const row = new MessageActionRow()
            .addComponents(
                new MessageButton().setCustomId('red').setLabel('🟥').setStyle('PRIMARY'),
                new MessageButton().setCustomId('orange').setLabel('🟧').setStyle('PRIMARY'),
                new MessageButton().setCustomId('blue').setLabel('🟦').setStyle('PRIMARY'),
                new MessageButton().setCustomId('green').setLabel('🟩').setStyle('PRIMARY'),
            );

        const embed = new MessageEmbed()
            .setColor('#f4900c')
            .setThumbnail(`https://image.tmdb.org/t/p/original/${res.results[num].poster_path}`)
            .setTimestamp()
            .setTitle('Popüler Filmler')
            .addFields(
                {name: `🟥 __${res.results[0].title}__`, value: `>>> 📜${cizgi}${res.results[0].release_date}${cizgi} 🌟${cizgi}${res.results[0].vote_average}${cizgi} 🌐 ${res.results[0].original_language}`, inline: true},
                {name: `🟧 __${res.results[1].title}__`, value: `>>> 📜${cizgi}${res.results[1].release_date}${cizgi} 🌟${cizgi}${res.results[1].vote_average}${cizgi} 🌐 ${res.results[1].original_language}`, inline: true},
                {name: `\u200B`, value: `\u200B`},
                {name: `🟦 __${res.results[2].title}__`, value: `>>> 📜${cizgi}${res.results[2].release_date}${cizgi} 🌟${cizgi}${res.results[2].vote_average}${cizgi} 🌐 ${res.results[2].original_language}`, inline: true},
                {name: `🟩 __${res.results[3].title}__`, value: `>>> 📜${cizgi}${res.results[3].release_date}${cizgi} 🌟${cizgi}${res.results[3].vote_average}${cizgi} 🌐 ${res.results[3].original_language}`, inline: true},
                {name: 'Filmler Hakkında Detaylı Bilgi İçin Alttaki Butonları Kullanabilirsiniz', value: '-------------------------------------------------------------------------------'},
            );
        // 修复过滤器逻辑,仅响应当前消息上的四个颜色按钮
        const filter = i => ['red', 'orange', 'blue', 'green'].includes(i.customId);
        // 发送消息后拿到消息实例,仅给当前消息绑定收集器,不污染整个频道
        const replyMsg = await interaction.editReply({embeds: [embed], components: [row]});
        const collector = replyMsg.createMessageComponentCollector({ filter, time: 15000 });

        collector.on('collect', async i => {
            // 按钮交互先占位响应,避免按钮点击3秒超时
            await i.deferUpdate();
            const btnIndexMap = {red:0, orange:1, blue:2, green:3};
            const targetIndex = btnIndexMap[i.customId];
            const tırnak = '`', space = ' ';
            const detailEmbed = new MessageEmbed()
                .setColor('DARK_GOLD')
                .setThumbnail(`https://image.tmdb.org/t/p/original${res.results[targetIndex].poster_path}`) 
                .setImage(`https://image.tmdb.org/t/p/original${res.results[targetIndex].backdrop_path}`)
                .setTitle(`Film`)
                .setDescription(`__**${res.results[targetIndex].title}**__`)
                .addFields(
                    { name: `Film Hakkında Bilgiler\n----------------------------`, value: `**Orjinal İsmi:** ${tırnak}${res.results[targetIndex].original_title}${tırnak}\n${space}\n**Orjinal Dili:** ${tırnak}${res.results[targetIndex].original_language}${tırnak} **Yapım Yılı:** ${tırnak}${res.results[targetIndex].release_date}${tırnak} **Puanı:**${tırnak}☆ ${res.results[targetIndex].vote_average}${tırnak}`},
                )
                .addField(`Özet:`,`${tırnak}${res.results[targetIndex].overview}${tırnak}`);
            
            await i.editReply({ embeds: [detailEmbed], components: []});
        });

        collector.on('end', collected => console.log(`Collected ${collected.size} items`));
    }
    else if(getChoices === 'vizyondakiler') {
        await interaction.editReply('Vizyondakiler !')
    }
}
关键改动说明
  • 所有交互在做耗时操作前先调用deferReply/deferUpdate占位,从根源解决超时导致的已确认报错。
  • 统一用await处理异步逻辑,去掉then混写的方式,避免时序错乱。
  • 修正过滤器和收集器绑定范围,不会误响应其他交互。
  • 调用deferReply后所有原交互的响应用editReply,不会重复调用reply触发报错。
  • 去掉了重复的embed声明代码,用映射表匹配按钮对应的电影下标,减少冗余代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 18:06:18