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

discord.py中View按钮交互失效,关联RESUMED session问题求助

问题原因

当Discord Bot的WebSocket会话重连(日志显示"Shared ID None has successfully RESUMED session")时,之前发送的临时View会失效。这是因为临时View的交互处理逻辑依赖于当前会话的内存状态,会话重连后,Bot无法关联旧View的按钮交互到对应的回调方法,导致出现"This interaction failed"错误。

解决思路与实现

1. 改用持久化View(Persistent Views)

持久化View会在Bot启动时注册,并且通过自定义custom_id关联交互,不受会话重连的影响。需要做以下修改:

修改ReviewView类

  • 初始化时设置persistent=True
  • 避免直接存储discord.User对象(无法序列化),改用用户ID、服务器ID和楼层参数
  • 给按钮设置包含关键参数的唯一custom_id
from discord import ui, ButtonStyle, Color, Interaction, Embed
from discord.utils import get

class ReviewView(ui.View):
    def __init__(self, user_id: int, guild_id: int, floor: int):
        super().__init__(persistent=True)
        self.user_id = user_id
        self.guild_id = guild_id
        self.floor = floor
        # 为按钮设置唯一custom_id,包含必要参数
        self.approve_button.custom_id = f"review_accept_{user_id}_{guild_id}_{floor}"

    @ui.button(label="Accept", style=ButtonStyle.success)
    async def approve_button(self, interaction: Interaction, button: ui.Button):
        # 从Bot实例获取服务器和用户对象
        guild = interaction.client.get_guild(self.guild_id)
        if not guild:
            await interaction.response.send_message("无法找到目标服务器", ephemeral=True)
            return
        
        user = guild.get_member(self.user_id)
        if not user:
            await interaction.response.send_message("用户已退出服务器", ephemeral=True)
            return

        embed = interaction.message.embeds[0]  
        embed.color = Color.green() 

        role = get(guild.roles, name=f"F{self.floor} Carrier")
        if not role:
            await interaction.response.send_message(f"角色F{self.floor} Carrier不存在", ephemeral=True)
            return

        # 检查并添加Carry Team角色
        user_has_carry_team = any(r.name == "Carry Team" for r in user.roles)
        if not user_has_carry_team:
            carry_team_role = get(guild.roles, name="Carry Team")
            if carry_team_role:
                await user.add_roles(carry_team_role)

        # 构建通知Embed
        dm_embed = Embed(
            title=f"你的地牢楼层{self.floor}申请已通过",
            description="感谢加入我们的代打计划!当有你提供的代打服务需求时,会@你通知。"
        )
        dm_embed.add_field(name="规则", value="<#990437238926110730>")
        dm_embed.add_field(name="审批人", value=f"{interaction.user.mention}", inline=False)
        dm_embed.set_author(name=interaction.user.name, icon_url=interaction.user.display_avatar.url)
        dm_embed.timestamp = interaction.created_at
        dm_embed.color = Color.green()

        try:
            await user.send(embed=dm_embed)
        except discord.Forbidden:
            print(f"用户{user.id}关闭了服务器DM,已在代打频道发送通知")
            carrier_chat = guild.get_channel(990438688561463297)
            if carrier_chat:
                await carrier_chat.send(embed=dm_embed)
        except Exception as e:
            print(f"发送通知时发生错误: {str(e)}")
            await interaction.response.send_message("发送通知失败", ephemeral=True)

        # 更新消息和角色
        await interaction.message.edit(embed=embed)
        await user.add_roles(role)
        await interaction.response.send_message(f"{user.mention}的申请已被{interaction.user.mention}通过", ephemeral=False)

在Bot启动时注册持久化View

需要在on_ready事件中注册View,确保Bot启动后能处理所有关联的custom_id交互:

@bot.event
async def on_ready():
    # 注册持久化View,初始化参数仅用于占位,实际使用时会通过custom_id匹配
    await bot.add_view(ReviewView(user_id=0, guild_id=0, floor=0))
    print(f"Bot {bot.user}已启动,持久化View已注册")

发送View时传入正确参数

在/apply命令中创建View时,传入用户ID、服务器ID和楼层,而不是直接传用户对象:

# 假设这是/apply命令的回调部分
async def apply_command(interaction: Interaction, floor: int):
    # 构建申请Embed(根据你的需求自行实现)
    apply_embed = Embed(title=f"新的楼层{floor}代打申请", description=f"申请人: {interaction.user.mention}")
    apply_embed.color = Color.blue()

    # 创建持久化View
    view = ReviewView(user_id=interaction.user.id, guild_id=interaction.guild.id, floor=floor)
    # 发送到员工频道(替换为你的员工频道ID)
    staff_channel = interaction.guild.get_channel(1234567890)
    await staff_channel.send(embed=apply_embed, view=view)
    await interaction.response.send_message("申请已提交,请等待审批", ephemeral=True)

2. 确保Bot Intents配置正确

需要启用members intent,这样Bot才能通过用户ID获取服务器成员对象。在Bot初始化时配置:

import discord

intents = discord.Intents.default()
intents.members = True

bot = discord.Bot(intents=intents)

同时,要在Discord开发者门户的Bot页面中开启"Server Members Intent"权限。

3. 优化异常处理

避免使用except Exception:捕获所有异常,改为捕获具体异常并打印错误信息,便于排查问题,比如DM失败通常是discord.Forbidden异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:34:56