discord.py使用discord_components做商店按钮触发interaction failed问题
问题根因
你遇到的两个问题核心原因有3个:
- 未及时响应Discord交互:Discord要求按钮点击事件触发后3秒内必须回应用户交互,你当前代码只监听了点击事件修改页码,完全没有对交互做响应,超过3秒就会触发“This interaction failed”报错,部分情况下还会阻塞消息编辑流程导致耗时变长。
- 全局页码变量冲突:使用全局变量
position_in_shop_items存储当前页码,多个用户同时调用商店命令时会互相篡改页码,甚至会触发索引越界报错拖慢运行速度。 - 页码边界计算错误:列表索引从0开始,你当前用
len(shop_items)作为最大页码判断条件,会出现索引越界问题,异常捕获后静默失败也会拉长运行耗时。
修复方案
- 每次获取到按钮点击响应后第一时间调用
await response.respond()完成交互校验,避免超时报错 - 移除全局页码变量,将页码存储在当前命令的上下文变量中,避免多用户冲突
- 修正页码边界计算逻辑,最大合法页码为
len(shop_items) - 1,加减页码时做边界限制 - 移除冗余的YAML加载逻辑,减少不必要的资源消耗
修复后核心代码示例
import yaml import discord from discord.ext import commands from discord_components import DiscordComponents, Button, ButtonStyle from pymongo import MongoClient # 优化后的物品加载逻辑,提前仅加载一次,不用每次调用命令重复加载 with open('items.yaml', 'r') as yaml_file: item_list_yaml = yaml.safe_load(yaml_file) shop_items = [] for item_id, item_info in item_list_yaml.items(): shop_items.append({ 'name': item_info['name'], 'buy_price': item_info['buy_price'], 'amount': item_info['amount'], 'sell_price': item_info['sell_price'], 'item_id': item_id, 'emoji': item_info['emoji'], }) class Shop(commands.Cog): def __init__(self, client): self.client = client self.cluster = MongoClient(DB) self.collection = self.cluster.users.eco DiscordComponents(client) @commands.command(name="shop") async def main_shop(self, ctx): # 把页码存在当前命令的局部变量里,不全局共享 current_page = 0 max_page = len(shop_items) - 1 # 生成embed的公共方法抽离,减少重复代码 def generate_embed(page): item = shop_items[page] desc = f"{item['emoji']}**{item['name']}**\n" if item['buy_price'] is not None: desc += f"**Buy Price: `{item['buy_price']}`<:coins:872444592115568661>**\n" if item['sell_price'] is not None: desc += f"**Sell Price: `{item['sell_price']}`<:coins:872444592115568661>**" return discord.Embed(title="Shop", description=desc) # 生成按钮的公共方法 def generate_buttons(page): buttons = [] if page > 0: buttons.append(Button(style=ButtonStyle.grey, label="<-", custom_id="prev")) if page < max_page: buttons.append(Button(style=ButtonStyle.grey, label="->", custom_id="next")) return [buttons] # 首次发送商店消息 current_embed = generate_embed(current_page) current_buttons = generate_buttons(current_page) shop_msg = await ctx.send(embed=current_embed, components=current_buttons) while True: # 只监听当前消息的按钮点击,避免其他用户的按钮点击触发当前逻辑 try: response = await self.client.wait_for( "button_click", check=lambda i: i.message.id == shop_msg.id and i.user == ctx.author, timeout=60 # 加超时自动退出,避免资源占用 ) except: # 超时后禁用按钮,结束逻辑 await shop_msg.edit(components=[]) return # 第一时间响应交互,避免超时报错 await response.respond(type=6) # type=6是无感知响应,不会弹额外消息 # 处理页码变更 if response.custom_id == "next" and current_page < max_page: current_page += 1 elif response.custom_id == "prev" and current_page > 0: current_page -= 1 # 更新消息内容 new_embed = generate_embed(current_page) new_buttons = generate_buttons(current_page) await shop_msg.edit(embed=new_embed, components=new_buttons)
内容的提问来源于stack exchange,提问作者Nick403
相关产品推荐
相关产品推荐

