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

Discord.js v14中String Select Collector交互失败问题求助

Discord.js v14 选择菜单触发“Interaction Failed”问题解决

核心问题分析

  1. 未完成交互回应:Discord要求所有组件交互必须在3秒内通过reply/deferReply/update等方法确认,仅执行console.log会导致平台判定交互超时,触发错误。
  2. CustomID 设计不合理:当前使用client.user.id(机器人自身ID)生成组件ID,会导致所有用户的组件ID完全一致,可能引发过滤器匹配冲突,且无法区分不同用户的交互。

修复后的完整代码

import {
  ActionRowBuilder,
  TextInputBuilder,
  TextInputStyle,
  Message,
  ButtonBuilder,
  ButtonStyle,
  ComponentType,
  ModalBuilder,
  StringSelectMenuBuilder,
  StringSelectMenuOptionBuilder,
} from "discord.js";

import CustomClient from "@/bot/classes/client";

const teams = [...];

export default {
  run: async (client: CustomClient, interaction: Message) => {
    try {
      // 使用消息发起者的ID生成唯一组件标识
      const userId = interaction.author.id;

      const unlockButton = new ButtonBuilder()
        .setCustomId(`unlock-${userId}`)
        .setStyle(ButtonStyle.Primary)
        .setLabel("🔓 Clique para acessar o canal...");

      const unlockButtonReply = await interaction.reply({
        components: [
          new ActionRowBuilder<ButtonBuilder>().setComponents(unlockButton),
        ],
      });

      const unlockButtonReplyCollector =
        unlockButtonReply.createMessageComponentCollector({
          componentType: ComponentType.Button,
          filter: (i) => i.customId === `unlock-${userId}` && i.user.id === userId,
          time: 120_000,
        });

      unlockButtonReplyCollector.on(
        "collect",
        async (unlockButtonInteraction) => {
          const emailInput = new TextInputBuilder()
            .setCustomId(`email-${userId}`)
            .setLabel("Digite seu email")
            .setRequired(true)
            .setMinLength(5)
            .setStyle(TextInputStyle.Short);

          const modalEmail = new ModalBuilder()
            .setCustomId(`modal-${userId}`)
            .setTitle("Liberação do Canal de Notícias")
            .setComponents([
              new ActionRowBuilder<TextInputBuilder>().addComponents(
                emailInput
              ),
            ]);

          await unlockButtonInteraction.showModal(modalEmail);

          const modalEmailInteraction =
            await unlockButtonInteraction.awaitModalSubmit({
              filter: (i) => i.customId === `modal-${userId}` && i.user.id === userId,
              time: 120_000,
            });

          const email = modalEmailInteraction.fields.getField(
            `email-${userId}`
          );

          const username = modalEmailInteraction.user.username;

          const teamSelectReply = await modalEmailInteraction.reply({
            components: [
              new ActionRowBuilder<StringSelectMenuBuilder>().setComponents(
                new StringSelectMenuBuilder()
                  .setCustomId(`team-${userId}`)
                  .setPlaceholder("Selecione o seu time do coração!")
                  .setMinValues(1)
                  .setMaxValues(1)
                  .addOptions(
                    teams.map((time) =>
                      new StringSelectMenuOptionBuilder()
                        .setLabel(time.label)
                        .setValue(time.value)
                    )
                  )
              ),
            ],
            ephemeral: true, // 可选:设置为临时消息仅当前用户可见
          });

          try {
            const teamSelectInteraction = await teamSelectReply.awaitMessageComponent({
              componentType: ComponentType.StringSelect,
              filter: (i) => i.customId === `team-${userId}` && i.user.id === userId,
              time: 120000,
            });

            // 必须完成交互回应,这里选择更新原消息
            await teamSelectInteraction.deferUpdate();
            // 也可以发送确认消息:
            // await teamSelectInteraction.reply({ content: `你选择了团队:${teamSelectInteraction.values[0]}`, ephemeral: true });
            
            const team = teamSelectInteraction.values[0];
            console.log(team);
          } catch (error) {
            console.error("选择菜单交互超时或出错:", error);
          }
        }
      );
    } catch (error) {
      console.log("全局执行错误:", error);
    }
  },
};

关键修复说明

  • 添加交互确认:在获取选择菜单交互后,调用deferUpdate()完成平台要求的交互回应,避免超时错误。
  • 唯一组件ID:用interaction.author.id替换client.user.id生成组件CustomID,同时在过滤器中添加用户ID校验,确保交互仅对发起者生效。
  • 优化异步逻辑:将.then().catch()改为try/catch结构,提升代码可读性和错误处理能力。

内容的提问来源于stack exchange,提问作者Luis Henrique Valgoi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 14:41:27