JDA机器人封禁/踢出用户时即便用户私信开放也无法发送DM问题排查
问题原因
- 核心为异步任务执行顺序异常:JDA的
queue()方法属于异步非阻塞调用,提交私信发送任务后,程序不会等待该任务执行完成,就会立即触发后续的踢人逻辑。绝大多数场景下踢人操作会先执行完毕,此时被操作用户已与机器人无共同服务器,Discord官方策略会直接拒绝机器人的私信发送请求,即便用户此前开放了私信权限也无法成功发送。 - 代码存在非功能性拼写错误:私信内容中
he reason缺少首字母T,应为The reason,不影响发送成功率但会导致内容展示异常。
修复方案
调整异步任务的串联逻辑,将踢人/封禁操作绑定到私信发送任务的执行链路后,确保无论私信发送成功或失败,都会在私信请求处理完成后再执行用户移除操作,避免用户提前被移出服务器导致私信被Discord官方策略拦截。封禁场景的修复逻辑完全一致,仅需将kick方法替换为对应的封禁方法即可。
修复后的代码如下:
public static void kickUser(@NotNull Member member, @NotNull Member author, @NotNull String reason, long userId, @NotNull SlashCommandEvent event) { String guildName = event.getGuild().getName(); // 构造发送私信的RestAction RestAction<Message> sendDmAction = event.getJDA() .openPrivateChannelById(userId) .flatMap(channel -> channel.sendMessage( """ Hey there, sorry to tell you but unfortunately you have been kicked from the guild %s. If you think this was a mistake, please contact a moderator or admin of the guild. The reason for the kick is: %s """.formatted(guildName, reason))); // 先执行私信发送,无论成功失败都执行踢人逻辑 sendDmAction .onErrorFlatMap(throwable -> { logger.info("I could not dm the user '{}' to inform them that they were kicked. {}", userId, throwable); // 异常时返回空RestAction,保证后续流程正常执行 return RestAction.empty(); }) // 私信流程处理完成后再执行踢人操作 .flatMap(ignored -> event.getGuild().kick(member, reason)) .flatMap(ignored -> event.reply(member.getUser().getAsTag() + " was kicked by " + author.getUser().getAsTag() + " for: " + reason)) .queue(); logger.info(" '{} ({})' kicked the user '{} ({})' due to reason being '{}'", author.getUser().getAsTag(), author.getIdLong(), member.getUser().getAsTag(), userId, reason); }
内容的提问来源于stack exchange,提问作者Yusuf.I
相关产品推荐
相关产品推荐

