Discord机器人重复触发反应事件且嵌入消息发送异常问题
Discord机器人重复触发
on_raw_reaction_add事件的解决方案 问题描述
执行!sendmessage命令后,机器人会给服务器内非机器人成员发送DM并添加✅、❌、🟡三个反应。但用户对这些DM添加反应时,机器人会重复触发on_raw_reaction_add事件,多次发送标题为“Reaction Log”的嵌入消息,而非仅生成一条记录。
问题原因
- 原代码过滤机器人自身反应的逻辑有漏洞:
payload.member在DM场景下可能为None,导致无法拦截机器人自己添加反应的操作,进而触发多余日志。 - DM频道无
guild_id,原代码直接通过guild.get_member获取用户会引发潜在错误,甚至导致事件重复处理。 - 未限制仅处理指定的三个反应,可能触发不必要的日志。
修复后的代码
import discord from discord.ext import commands from collections import defaultdict intents = discord.Intents.all() bot = commands.Bot(command_prefix='!', intents=intents) # 记录已处理的反应,避免重复触发 processed_reactions = defaultdict(set) @bot.command(name='sendmessage') async def send_message(ctx, *, message: str): for member in ctx.guild.members: if not member.bot: dm_channel = await member.create_dm() sent_message = await dm_channel.send(message) await sent_message.add_reaction("✅") await sent_message.add_reaction("❌") await sent_message.add_reaction("🟡") @bot.event async def on_raw_reaction_add(payload): # 过滤机器人自身的反应,用user_id判断更可靠 if payload.user_id == bot.user.id: return # 只处理指定的三个反应 allowed_emojis = {"✅", "❌", "🟡"} if payload.emoji.name not in allowed_emojis: return # 生成唯一标识,判断该反应是否已处理 reaction_key = (payload.user_id, payload.message_id, payload.emoji.name) if reaction_key in processed_reactions[payload.message_id]: return processed_reactions[payload.message_id].add(reaction_key) # 区分场景获取用户信息:服务器内用guild成员,DM用fetch_user if payload.guild_id: guild = bot.get_guild(payload.guild_id) member = guild.get_member(payload.user_id) else: member = await bot.fetch_user(payload.user_id) # 验证消息是否为机器人发送 channel = bot.get_channel(payload.channel_id) if not channel: return try: message = await channel.fetch_message(payload.message_id) except discord.NotFound: return if message.author != bot.user: return # 发送日志 log_channel = bot.get_channel(1095834015421972550) if not log_channel: return embed = discord.Embed(title="Reaction Log", color=0x00ff00) embed.add_field(name="User", value=f"{member.mention} ({member.id})", inline=True) embed.add_field(name="Reaction", value=payload.emoji.name, inline=True) # 处理DM场景下无角色的情况 if payload.guild_id: embed.add_field(name="Roles", value=" ".join([role.mention for role in member.roles]), inline=False) else: embed.add_field(name="Roles", value="无(DM场景)", inline=False) embed.add_field(name="Nickname", value=member.nick or "无", inline=True) # 处理DM场景下无服务器加入时间的情况 if payload.guild_id and member.joined_at: embed.add_field(name="Joined At", value=member.joined_at.strftime("%Y-%m-%d %H:%M:%S"), inline=True) else: embed.add_field(name="Joined At", value="无(DM场景)", inline=True) await log_channel.send(embed=embed)
关键修复点
- 改用
payload.user_id == bot.user.id过滤机器人自身反应,规避DM场景下payload.member为None的漏洞。 - 新增
processed_reactions集合记录已处理的反应,彻底防止重复触发事件。 - 区分服务器和DM场景获取用户信息,避免报错。
- 限制仅处理指定的三个emoji,过滤不必要的反应操作。
- 增加异常处理,避免因消息不存在或日志频道无效导致的崩溃。
内容的提问来源于stack exchange,提问作者Technical
相关产品推荐
相关产品推荐

