discord.py on_message_edit事件随机误触发问题排查
问题根因
- 误触发核心来源:Discord的
on_message_edit事件不是只有用户手动修改消息文本才会触发。消息附带的链接预览加载完成、消息系统标记(flag)更新、附件状态变更等不改动content字段的元数据更新,都会触发该事件。初始监听代码没有做内容一致性校验,事件触发就发提示,必然出现前后文本完全一致的误报。 - 运行方式错误:将两个功能拆分到不同文件,同时启动两个独立进程、用同一个bot令牌连接Discord网关,会导致事件被重复广播、投递顺序混乱,进一步提升随机误触发概率,Discord官方不允许同一bot账号无意义建立多个网关连接。
- 之前修复代码的具体错误:
- 事件注册逻辑完全错误:把
on_message_edit的装饰器注册写在on_message事件的判断分支内部,会导致事件被重复注册,触发次数随消息接收量持续递增,逻辑完全不可控。 - 过滤规则无效:
id = id是无意义的自赋值,且直接将message.author(用户/成员对象)和整数ID做等值比较属于类型不匹配,根本无法命中过滤规则;也没有做bot账号的通用过滤,bot自身发消息触发的事件也会被处理。 - 指令逻辑失效:自定义
on_message事件后没有调用await bot.process_commands(message),所有前缀指令都无法正常响应。 - 存在未定义变量:修复代码中
channel = bot.get_channel(channel)的传入参数channel从未被赋值,运行到该行会直接抛出名称错误。 - 之前遇到的
unresolved reference报错,本质是变量作用域错误,对应位置没有正确定义/引入author相关变量。
- 事件注册逻辑完全错误:把
修复步骤
- 合并两个功能到同一个bot实例,禁止拆分多文件启动多个进程用同一令牌登录,从根源避免多连接导致的事件混乱。
- 在
on_message_edit事件最前端增加两层强制过滤:- 消息发送者为bot(包括当前bot自身)时直接return,不处理任何bot账号触发的消息编辑事件
- 编辑前后
content字段完全一致时直接return,过滤所有非文本修改触发的无效事件,这是解决误报的核心逻辑
- 所有事件注册统一放在代码顶层,禁止嵌套在其他函数/事件逻辑内部。
- 若需要自定义
on_message全局消息处理逻辑,必须在逻辑末尾添加await bot.process_commands(message),保证前缀指令能正常被识别执行。
修复后参考代码
import discord from discord.ext import commands from googlesearch import search # 对应你使用的谷歌搜索依赖库 # 两个功能共用同一个bot实例,注意提前在开发者后台开启相关权限意图 bot = commands.Bot(command_prefix='!', intents=discord.Intents.all()) @bot.event async def on_message_edit(before, after): # 过滤bot账号的消息编辑事件 if after.author.bot: return # 过滤内容无实际变化的编辑事件 if before.content == after.content: return # 正常编辑提示逻辑 embed = discord.Embed( timestamp=after.created_at, description = f"<@!{before.author.id}>**的消息在** <#{before.channel.id}>**被编辑**", colour = discord.Colour(0x00FF00) ) embed.set_author(name=f'{before.author.name}#{before.author.discriminator}', icon_url=before.author.avatar.url) embed.set_footer(text=f"作者ID:{before.author.id} • 消息ID: {before.id}") embed.add_field(name='编辑前:', value=before.content + "\u200b", inline=False) embed.add_field(name="编辑后:", value=after.content + "\u200b", inline=False) # 直接用消息所在频道发送,不需要硬编码频道ID调用get_channel await before.channel.send(embed=embed) @bot.command() async def question(ctx,*, query): author = ctx.author.mention await ctx.send(f"这是和你的问题相关的链接 {author} !") async with ctx.typing(): for j in search(query, tld="co.in", num=1, stop=1, pause=1): await ctx.send(f"\n {j}") # 无特殊全局消息处理需求可以删掉整个on_message事件,bot默认会自动处理指令 @bot.event async def on_message(message): # 在此处编写自定义全局消息处理逻辑 await bot.process_commands(message) # 该行必须保留,否则指令无法响应 bot.run('替换为你的bot令牌')
前置配置提醒:需要提前在Discord开发者后台对应Bot的设置页,开启「Message Content Intent」开关,否则bot无法接收消息正文内容,编辑事件也拿不到
content字段,功能会完全失效。
内容的提问来源于stack exchange,提问作者NoobieAtCoding
相关产品推荐
相关产品推荐

