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

Discord机器人重复触发反应事件且嵌入消息发送异常问题

Discord机器人重复触发on_raw_reaction_add事件的解决方案

问题描述

执行!sendmessage命令后,机器人会给服务器内非机器人成员发送DM并添加✅、❌、🟡三个反应。但用户对这些DM添加反应时,机器人会重复触发on_raw_reaction_add事件,多次发送标题为“Reaction Log”的嵌入消息,而非仅生成一条记录。

问题原因

  1. 原代码过滤机器人自身反应的逻辑有漏洞:payload.member在DM场景下可能为None,导致无法拦截机器人自己添加反应的操作,进而触发多余日志。
  2. DM频道无guild_id,原代码直接通过guild.get_member获取用户会引发潜在错误,甚至导致事件重复处理。
  3. 未限制仅处理指定的三个反应,可能触发不必要的日志。

修复后的代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:57:49