重连后Discord Bot无法更新历史消息的技术求助
我之前也碰到过几乎一模一样的问题!你的Bot重连后拿不到旧消息,本质是Discord.NET的缓存机制限制和Socket/Rest消息对象的类型差异共同导致的,具体原因和修复方法如下:
核心问题拆解
重连后本地缓存清空,默认查询没触发API请求
Bot断开重连后,DiscordSocketClient的本地消息缓存会被完全重置——之前发送的那条订阅消息不会自动加载到新缓存里。默认情况下,GetMessageAsync会先查本地缓存,找不到的话虽然理论上会去API拉取,但在某些缓存配置逻辑下,可能不会触发API请求,直接返回null。SocketUserMessage类型转换失败
就算你侥幸触发了API请求拿到消息,返回的对象是RestUserMessage,而不是你代码里用的SocketUserMessage——后者是仅存在于Socket客户端缓存里的专属对象。用as SocketUserMessage转换时,类型不匹配就会得到null,这才是你代码里拿不到消息的关键坑点!
快速修复方案
直接修改你的消息获取代码,这是最可靠的解决方式:
// 替换原来的消息获取行 var message = await channel.GetMessageAsync(playtimeFeed.MessageId, CacheMode.ForceDownload); if (message == null) return;
这么改有两个好处:
CacheMode.ForceDownload会绕过本地缓存,直接向Discord API请求目标消息,只要消息还在频道里、Bot有权限,就能拿到- 去掉
as SocketUserMessage的强制转换,直接用通用的IMessage接口——ModifyAsync是IMessage的标准方法,不管是缓存里的Socket消息还是API返回的Rest消息,都能正常调用
可选的缓存优化(辅助方案)
如果希望重连后缓存能自动包含更多历史消息,可以调整DiscordSocketConfig的配置,但这个方案只能作为辅助,不能替代上面的强制API请求:
_client = new DiscordSocketClient( new DiscordSocketConfig { LogLevel = LogSeverity.Verbose, AlwaysDownloadUsers = true, MessageCacheSize = 1000, // 必须开启这几个网关意图(Discord开发者后台也要同步开启) GatewayIntents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | GatewayIntents.MessageContent, // 可选:允许重试限流请求 DefaultRetryMode = RetryMode.RetryRatelimit } );
注意:一定要在Discord开发者后台的Bot设置里,开启
Server Members Intent和Message Content Intent,否则网关意图配置不会生效。不过就算开了缓存,重连后也没法保证100%包含所有旧消息,所以还是优先用第一个方案。
额外排查建议
- 在
message == null的分支加个日志,把playtimeFeed里的三个ID打出来,确认和Discord频道里的实际消息ID完全一致(有时候可能不小心存错ID) - 再检查一遍Bot的频道权限:确保有
查看频道和读取消息历史的权限,频道没有单独给Bot设权限黑名单
内容的提问来源于stack exchange,提问作者MX D

