分类: Discord 机器人开发
写给 Discord 机器人开发者的 2026 年 9 月 API 变更汇总 - 文件 20MiB·斜杠命令多行输入·年龄验证(Age Assurance)·邀请目标用户·shard 必填,用 discord.py 2.7.1 应对(Python 示例)🗞️
本文译自韩语原文。
要点速览
把 2026 年 8 月底到 9 月 Discord 开发者更新日志里发布的 7 项变更,按机器人开发者的角度整理出来,并分成必须改代码的和不用改的。discord.py 2.7.1 里还没有的功能,用直接调用端点的示例来应对。
- discord.py 2.7.1 · Python 3.13 · 基于 2026-09-30 官方更新日志确认(示例只做到语法·import 检查,在真实服务器上运行需要读者自行确认)
- 必须改代码的只有两处:大型机器人分片应用的 shard 查询参数(9/15),以及开启 PRUNE_REQUIRES_ADMIN 的服务器上的清理权限(8/27)
- 文件默认上限已提高到 20 MiB,但 discord.py 2.7.1 的 guild.filesize_limit 仍然返回 10 MiB → 请以 interaction.filesize_limit 为准
- 字符串选项里可能出现换行,所以用 splitlines() 接收;邀请目标用户端点用 bot.http.request(Route(...)) 直接调用
目录15 项
大家好!我是 Mojangcam 😎
上一篇 第 24 篇 里,我们提前演练了 11 月 16 日就要生效的频道混淆。之后短短一个月,Discord 开发者更新日志又接连发布了 7 条分量不轻的公告。每一条都不长,可放在一起看,就会搞不清"我的机器人到底要改哪里?"
所以今天不做新功能,而是站在机器人开发者的角度,把 2026 年 8 月底到 9 月的变更一次性理清楚。每一项都先回答"会影响我的机器人吗?"和"需要改代码吗?",再附上基于 discord.py 2.7.1 的应对代码。库里还没有的功能,就用直接调用端点的方法补上 🛠️
本文你会学到
- 用一张表看懂 9 月的 7 项变更(要改的 / 不用改的)
- 文件上限已经涨到 20 MiB,库却还说是 10 MiB 的陷阱
- 斜杠命令字符串选项开始出现换行之后该怎么处理
- 用
Route直接调用 discord.py 里没有的邀请目标用户(target user)端点 - 大型机器人分片应用的
shard查询参数、PRUNE_REQUIRES_ADMIN权限检查 - 因年龄验证(Age Assurance)和资料隐私设置看不到自定义状态时,如何安全地读取
📌 一览 - 9 月的 7 项变更
| 日期 | 变更 | 影响我的机器人吗? | 需要改代码? |
|---|---|---|---|
| 8/27 | 服务器功能 PRUNE_REQUIRES_ADMIN (Breaking) |
仅限使用成员清理(prune)功能的机器人 | 添加权限检查 |
| 9/3 | 文件上传默认上限 10 MiB → 20 MiB | 所有发送文件的机器人(往好的方向) | 有计算上限的代码时 |
| 9/11 | 斜杠命令:字符串选项多行输入、命令模糊搜索、切换频道时记住命令 | 所有接收字符串选项的机器人 | 只需处理换行 |
| 9/15 | 大型机器人分片应用调用 GET /users/@me/guilds 时必须带 shard (Breaking) |
仅限大型机器人分片应用 | 必须(符合条件时) |
| 9/17 | 资料设为隐私时,自定义状态会从 Presence 中移除 | 读取状态的机器人 | 确认 None 处理 |
| 9/18 | 新增 4 个邀请目标用户端点 | 创建邀请链接的机器人(可选) | 想用的话 |
| 9/22 | 年龄验证(Age Assurance)全球推行 | 无(只需观察行为变化) | 无 |
先说结论:必须改的只有两处。使用大型机器人分片的应用要加 shard 查询参数,有成员清理功能的机器人要加权限检查。其余的要么知道就行,要么反而让机器人更好用 😌
📌 准备工作
- Python 3.8 以上(示例在 Python 3.13 上做了语法检查)
- discord.py 2.7.1 — 截至 2026-09-30 的最新版本。3 月之后没有发布新版本,所以今天讲的 9 月变更库里还没有跟进
- python-dotenv — 用来把令牌分离到 .env 文件
- 已经邀请了机器人的测试服务器(有管理员权限会更方便)
pip install discord.py==2.7.1 python-dotenv在项目文件夹里创建 .env 文件,填入令牌。
DISCORD_TOKEN=여기에_봇_토큰💡 .env 一定要加进 .gitignore。令牌一旦被传到 GitHub,Discord 会自动检测并作废这个令牌 😱
今天的示例因为要读取自定义状态,需要在开发者门户 → Bot 标签页里开启 Server Members Intent 和 Presence Intent。如果不需要读取状态,可以删掉 intents.presences = True 这一行,门户设置也可以跳过。
📌 1. 文件上传默认上限 20 MiB(9/3)
变更内容:默认文件上传上限从 10 MiB 提高到了 20 MiB。不只是用户,机器人、Webhook、交互响应也同样适用。
影响我的机器人吗?:如果你的机器人会发文件,这纯粹是好消息。在没有助力(Boost)的服务器上,15 MB 的日志文件或图片现在也能传上去了。
不过这里有个陷阱。打开 discord.py 2.7.1 的源码看看,默认上限还是旧的值。
# discord/utils.py (2.7.1)
DEFAULT_FILE_SIZE_LIMIT_BYTES = 10485760 # 10 MiB所以在没有助力的服务器上,guild.filesize_limit 和 ctx.filesize_limit 仍然返回 10 MiB。如果你用这个值写了"超过上限就不发送"之类的防御代码,那么机器人其实是在自己拒绝本来能发的文件 😅
正确做法是使用 Discord 在每次交互里一起发来的值。
@bot.tree.command(name="파일한도", description="显示机器人在这个服务器能上传的文件大小")
async def file_limit(interaction: discord.Interaction):
live = interaction.filesize_limit # Discord 随这次交互一起发来的值
cached = interaction.guild.filesize_limit if interaction.guild else None # 库内置的表
msg = f"Discord 告知的上限:**{live / MIB:.0f} MiB**"
if cached is not None:
msg += f"\ndiscord.py 表的值(guild.filesize_limit):{cached / MIB:.0f} MiB"
await interaction.response.send_message(msg, ephemeral=True)我们逐个拆开来看 💡
- interaction.filesize_limit:discord.py 2.6 新增的属性。它原样保存交互载荷里的
attachment_size_limit值,是 Discord 服务器此刻告诉你的上限,而不是库里的表。20 MiB 的变更会直接反映在这里。 - guild.filesize_limit:查看库里硬编码的按助力等级划分的表。在 2.7.1 中,0·1 级是 10 MiB,2 级 50 MiB,3 级 100 MiB。在下个版本修复之前,只当参考就好。
- MIB = 1024 * 1024:Discord 文档用的不是 MB,而是 MiB(1,048,576 字节)。按 20 MB(20,000,000 字节)算的话,会少大约 1 MB。
📌 2. 斜杠命令改进 - 多行输入·模糊搜索(9/11)
变更内容有三点。
- 字符串选项支持多行输入。用户可以用 Shift+Enter 换行后再发送。
- 命令选择窗口支持模糊搜索。只输入
/r a也能出现/role add。 - 切换频道后也会记住正在选的命令。
影响我的机器人吗?:第 1 点是关键。以前可以放心地认为字符串选项只有一行,现在会收到夹带 \n 的值。如果你的代码把选项值直接放进嵌入消息的标题、当作文件名或数据库键,或者记成单行日志,格式就可能被打乱。
处理起来很简单。只要养成按行拆分接收的习惯就行。
@bot.tree.command(name="여러줄", description="把多行输入的文字按行拆开显示")
@app_commands.describe(text="试试用 Shift+Enter 换行输入")
async def multiline(interaction: discord.Interaction, text: app_commands.Range[str, 1, 1000]):
lines = [line.strip() for line in text.splitlines() if line.strip()]
if not lines:
await interaction.response.send_message("内容是空的!", ephemeral=True)
return
body = "\n".join(f"{i}. {line}" for i, line in enumerate(lines, start=1))
await interaction.response.send_message(f"一共收到 **{len(lines)} 行**。\n{body}")我们逐个拆开来看 💡
- text.splitlines():不管来的是
\n还是\r\n,都会按行切开。比split("\n")更安全。 - if line.strip():丢掉空行。支持多行输入后,肯定会有用户连按两次 Enter。
- app_commands.Range[str, 1, 1000]:字符串长度上限。变成多行之后更容易收到长文本,最好明确设定上限。Discord 一条消息最多 2,000 字,设成 1,000 字的话,加上编号再发回去也很安全。
- 必须是一行的地方:要用作标题、文件名、键的值,请用
text.replace("\n", " ")压成一行再用。
第 2 点模糊搜索是客户端选择命令名称时的功能。第 22 篇里做的选项自动补全回调并不会自动变成模糊搜索。不过用户今后会习惯"随便打几个字也能找到"的体验,所以建议不要把自动补全的过滤条件设得像 startswith 那么严格,而是像第 22 篇那样用 in(部分匹配)放宽一些 🔍
📌 3. 大型机器人分片应用必须带 shard 查询参数(9/15,Breaking)
变更内容:使用大型机器人分片(large bot sharding)的应用在调用 GET /users/@me/guilds(我的机器人所在的服务器列表)时,必须带上 shard 查询参数。不带就会收到 400 Bad Request。取值范围是 0 到 max_concurrency - 1,max_concurrency 在 Get Gateway Bot 响应的 session_start_limit 里。
影响我的机器人吗?:大型机器人分片是 Discord 专门为服务器数量非常多的机器人单独批准的方式。这个系列里做的这种规模的机器人不受影响。 官方文档也明确写了"不使用大型机器人分片的应用不受影响"。放心吧 😌
不过还是为符合条件的朋友写一下。discord.py 2.7.1 的 client.fetch_guilds() 没有 shard 参数(内部只发送 limit·before·after·with_counts),所以要直接调用端点。
async def fetch_all_guilds_by_shard(client: discord.Client) -> list:
"""给使用大型机器人分片的应用用。普通机器人直接用 client.fetch_guilds() 就行。"""
_, _, start_limit = await client.http.get_bot_gateway()
max_concurrency = start_limit["max_concurrency"]
guilds = []
for shard in range(max_concurrency):
route = Route("GET", "/users/@me/guilds")
data = await client.http.request(route, params={"shard": shard, "limit": 200})
guilds.extend(data)
return guilds我们逐个拆开来看 💡
- client.http.get_bot_gateway():调用
GET /gateway/bot,返回(shards, url, session_start_limit)三个值。第三个字典里的max_concurrency就是需要的值。 - Route("GET", "/users/@me/guilds"):
discord.http.Route是库在所有请求中都会用到的类。用from discord.http import Route导入。 - client.http.request(route, params=...):查询字符串通过
params传入。速率限制由库来处理。返回值是解析后的 JSON(服务器字典列表)。 - 文档的说明:如果需要完整列表,要遍历所有 shard 值再合并。所以这里用
range(max_concurrency)循环。
⚠️ bot.http 不是公开 API,而是库的内部对象。下个版本签名可能会变,等 discord.py 提供正式方法后,请换成正式方法。
📌 4. 自定义状态隐藏(9/17)+ 年龄验证 Age Assurance(9/22)
把两个放在一起,是因为结果一样。都是"机器人原本能看到的用户信息,从某天起看不到了"。
9/17 变更内容:如果用户的资料公开范围设为仅好友,或者设为好友和小型服务器而服务器成员超过 200 人,那么发往该服务器的 Presence Update 的 activities 里会去掉自定义状态。Playing·Streaming·Listening·Watching·Competing 等其他活动保持不变。
9/22 变更内容:年龄验证向全球推行。借用官方文档的原话,"应用会照常运行,但是"有四点可能看起来不一样。
- 资料设为隐私的用户,在 Presence 里可能看不到自定义状态(和上面 9/17 是同一件事)
- 带年龄限制的 Activity 可能会要求用户进行年龄组验证
- 由于父母设置的消费限额,部分购买可能会失败
- 通过 Social SDK 发送的私信会更常被归入消息请求
影响我的机器人吗?:不用改代码。但如果你的代码会从 member.activities 里取出自定义状态来用,就要把取不到的情况当作正常情况处理。以前可以假设"设置了状态的人就一定有",现在不行了。
@bot.tree.command(name="상태보기", description="读取成员的自定义状态(可能看不到)")
async def show_status(interaction: discord.Interaction, member: discord.Member):
custom = next((a for a in member.activities if isinstance(a, discord.CustomActivity)), None)
if custom is None:
text = "没有设置自定义状态,或者因为资料隐私设置,机器人看不到。"
else:
text = f"{custom.emoji or ''} {custom.name or ''}".strip() or "(只有表情的状态)"
await interaction.response.send_message(f"{member.display_name}: {text}", ephemeral=True)我们逐个拆开来看 💡
- member.activities:是一个元组。自定义状态、游戏、Spotify 混在一起,所以用
isinstance(a, discord.CustomActivity)挑出来。member.activity(单数)只给第一个,找自定义状态时不要用它。 - next(..., None):没有就是 None。现在这个 None 同时代表"没设置"和"被隐藏"两种情况,而机器人没有办法区分。所以提示文字把两种情况都写进去了。
- custom.name / custom.emoji:两者都是 Optional。也有只有表情的状态,所以用
or ''包了一下。 - Presence Intent:要让
member.activities有内容,intents.presences = True和开发者门户里的 Presence Intent 都必须开启。不开的话永远是空元组,就没法和"被隐藏"区分了。
📌 5. 邀请目标用户(target user)端点(9/18)
变更内容:新增了 4 个端点,可以给邀请链接加上"只有这些人能用"的名单。
| 操作 | 方法·路径 | 请求体 |
|---|---|---|
| 添加目标 | PUT /invites/{invite.code}/target-users/{user.id} |
无 |
| 移除目标 | DELETE /invites/{invite.code}/target-users/{user.id} |
无 |
| 批量添加 | POST /invites/{invite.code}/target-users/bulk-add |
user_ids 数组(最多 1,000 人) |
| 批量移除 | POST /invites/{invite.code}/target-users/bulk-delete |
user_ids 数组(最多 1,000 人) |
四个端点都要求是邀请的创建者,或者拥有 MANAGE_GUILD(管理服务器)权限,成功时返回 204(无响应体)。更新日志里还写到,创建邀请时就可以一并传入 target_user_ids 数组。
影响我的机器人吗?:不用也完全没问题。不过像第 33 篇的派对房间那样,要做"只有被邀请的人才能进来"的功能时,以前是靠频道权限覆盖来拦,现在可以把邀请链接本身做成特定用户专属了。
discord.py 2.7.1 的 create_invite() 没有这个选项。(虽然有个叫 target_user 的参数,但那指的是直播观看邀请里的主播,是另一个功能。特别容易搞混 😅)所以邀请照常创建,只有指定目标这一步直接调用。
@bot.tree.command(name="초대대상", description="创建只有指定的人才能使用的邀请链接")
@app_commands.describe(member="允许使用邀请链接的成员")
async def invite_target(interaction: discord.Interaction, member: discord.Member):
channel = interaction.channel
if not isinstance(channel, discord.TextChannel):
await interaction.response.send_message("请在文字频道里使用!", ephemeral=True)
return
await interaction.response.defer(ephemeral=True)
invite = await channel.create_invite(max_age=3600, max_uses=1, unique=True,
reason=f"{member} 专属邀请")
# discord.py 2.7.1 还没有对应的方法,所以直接调用端点
route = Route("PUT", "/invites/{code}/target-users/{user_id}",
code=invite.code, user_id=member.id)
await bot.http.request(route) # 成功时返回 204(无响应体)
await interaction.followup.send(
f"已创建 {member.mention} 专属邀请链接(1 小时,1 次):{invite.url}", ephemeral=True
)我们逐个拆开来看 💡
- channel.create_invite(max_age=3600, max_uses=1, unique=True):1 小时有效、只能用 1 次的邀请。因为
unique=True,不会复用已有邀请,而是新建一个。这个邀请的创建者是我们的机器人,所以机器人就是"邀请的创建者",拥有指定目标的权限。 - Route("PUT", "/invites/{code}/target-users/{user_id}", code=..., user_id=...):路径里的
{code}·{user_id}由关键字参数填入。上面的代码生成的地址是https://discord.com/api/v10/invites/<코드>/target-users/<유저ID>。(我亲自打印出来确认过。) - await bot.http.request(route):这是没有请求体的 PUT。要添加多个人的话,给
Route("POST", "/invites/{code}/target-users/bulk-add", code=...)传入json={"user_ids": [id1, id2]}即可。 - 先 defer:创建邀请 + 指定目标一共要发两次 HTTP 请求,可能超过 3 秒。先
defer(),再用followup.send()回复。
📌 6. 成员清理(prune)需要管理员权限(8/27,Breaking)
虽然是 9 月的文章,但这是 8 月最后一周的变更,所以一起讲。这是很容易漏掉的 Breaking Change。
变更内容:服务器所有者现在可以开启一个叫 PRUNE_REQUIRES_ADMIN 的服务器功能。开启后,查询预计清理人数(Get Guild Prune Count)和执行清理(Begin Guild Prune)都需要 ADMINISTRATOR 权限。没开启的服务器还是和现在一样,需要 MANAGE_GUILD + KICK_MEMBERS。
影响我的机器人吗?:只影响使用 guild.prune_members() 或 guild.estimate_pruned_members() 的机器人。如果某天突然开始报 403 Forbidden,那就是服务器所有者开启了这个功能。
@bot.tree.command(name="정리예상", description="计算 30 天内没有活动的成员有多少(不会真的踢出)")
@app_commands.describe(days="多少天没有活动就算作清理对象 (1~30)")
async def prune_estimate(interaction: discord.Interaction, days: app_commands.Range[int, 1, 30] = 30):
guild = interaction.guild
if guild is None:
await interaction.response.send_message("请在服务器里使用!", ephemeral=True)
return
perms = guild.me.guild_permissions
if "PRUNE_REQUIRES_ADMIN" in guild.features:
if not perms.administrator:
await interaction.response.send_message(
"这个服务器开启了 **PRUNE_REQUIRES_ADMIN**,机器人需要管理员权限。",
ephemeral=True,
)
return
elif not (perms.kick_members and perms.manage_guild):
await interaction.response.send_message(
"机器人需要 **踢出成员 + 管理服务器** 权限才能计算。", ephemeral=True
)
return
await interaction.response.defer(ephemeral=True)
count = await guild.estimate_pruned_members(days=days)
await interaction.followup.send(f"按 {days} 天计算,清理对象:**{count} 人**(只做了计算)", ephemeral=True)我们逐个拆开来看 💡
- guild.features:服务器已开启功能名称的字符串列表。里面有
"COMMUNITY"、"NEWS"这样的值,这次新增了"PRUNE_REQUIRES_ADMIN"。即使库不认识新值,它也会以字符串原样传过来,所以在 2.7.1 里也能直接检查。 - guild.me.guild_permissions:我们的机器人在服务器里的最终权限。
administrator·kick_members·manage_guild都在这里看。 - estimate_pruned_members(days=...):不会真的踢人,只返回数字。示例里特意只用了这个。真正踢人的
prune_members()无法撤销,建议再加一个确认按钮。 - 为什么要提前检查:直接调用的话,也只是报 403 失败而已。但是告诉用户准确的原因,比如"请给机器人管理员权限",和只显示"出错了",体验完全不同。
💡 8 月可能错过的变更
- 8/12 频道混淆 — 从 11/16 起,机器人看不到的频道会被隐藏。第 24 篇里有详细介绍。
- 8/5 附件选项的
file_types—ATTACHMENT选项和文件上传组件新增了"只接收这些扩展名"的过滤器。discord.py 2.7.1 里还没有(源码里找不到file_types),只能等库更新。 - 8/5 频道的
application_id可能为 null — 如果你的代码假设频道对象的application_id一定是 ID,请加上 None 处理。
📌 完整代码(可直接复制)
只用 sept_check.py 一个文件,上面的 5 个命令就都能运行。直接复制使用吧!
# discord.py 2.7.1 / Python 3.8+
# 2026 年 9 月 Discord API 变更检查机器人 (sept_check.py)
import os
import discord
from discord import app_commands
from discord.ext import commands
from discord.http import Route
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.getenv("DISCORD_TOKEN")
if not TOKEN:
raise SystemExit("❌ .env 文件里没有 DISCORD_TOKEN!")
intents = discord.Intents.default()
intents.members = True # 成员信息(需要在开发者门户里开启)
intents.presences = True # 用于查看自定义状态(需要在开发者门户里开启)
bot = commands.Bot(command_prefix="!", intents=intents)
MIB = 1024 * 1024
@bot.event
async def on_ready():
await bot.tree.sync()
print(f"✅ 已登录:{bot.user} / discord.py {discord.__version__}")
# ① 9/11 - 字符串选项多行输入
@bot.tree.command(name="여러줄", description="把多行输入的文字按行拆开显示")
@app_commands.describe(text="试试用 Shift+Enter 换行输入")
async def multiline(interaction: discord.Interaction, text: app_commands.Range[str, 1, 1000]):
lines = [line.strip() for line in text.splitlines() if line.strip()]
if not lines:
await interaction.response.send_message("内容是空的!", ephemeral=True)
return
body = "\n".join(f"{i}. {line}" for i, line in enumerate(lines, start=1))
await interaction.response.send_message(f"一共收到 **{len(lines)} 行**。\n{body}")
# ② 9/3 - 文件上传默认上限 20 MiB
@bot.tree.command(name="파일한도", description="显示机器人在这个服务器能上传的文件大小")
async def file_limit(interaction: discord.Interaction):
live = interaction.filesize_limit # Discord 随这次交互一起发来的值
cached = interaction.guild.filesize_limit if interaction.guild else None # 库内置的表
msg = f"Discord 告知的上限:**{live / MIB:.0f} MiB**"
if cached is not None:
msg += f"\ndiscord.py 表的值(guild.filesize_limit):{cached / MIB:.0f} MiB"
await interaction.response.send_message(msg, ephemeral=True)
# ③ 8/27 - PRUNE_REQUIRES_ADMIN 服务器功能
@bot.tree.command(name="정리예상", description="计算 30 天内没有活动的成员有多少(不会真的踢出)")
@app_commands.describe(days="多少天没有活动就算作清理对象 (1~30)")
async def prune_estimate(interaction: discord.Interaction, days: app_commands.Range[int, 1, 30] = 30):
guild = interaction.guild
if guild is None:
await interaction.response.send_message("请在服务器里使用!", ephemeral=True)
return
perms = guild.me.guild_permissions
if "PRUNE_REQUIRES_ADMIN" in guild.features:
if not perms.administrator:
await interaction.response.send_message(
"这个服务器开启了 **PRUNE_REQUIRES_ADMIN**,机器人需要管理员权限。",
ephemeral=True,
)
return
elif not (perms.kick_members and perms.manage_guild):
await interaction.response.send_message(
"机器人需要 **踢出成员 + 管理服务器** 权限才能计算。", ephemeral=True
)
return
await interaction.response.defer(ephemeral=True)
count = await guild.estimate_pruned_members(days=days)
await interaction.followup.send(f"按 {days} 天计算,清理对象:**{count} 人**(只做了计算)", ephemeral=True)
# ④ 9/18 - 邀请目标用户(target user)端点
@bot.tree.command(name="초대대상", description="创建只有指定的人才能使用的邀请链接")
@app_commands.describe(member="允许使用邀请链接的成员")
async def invite_target(interaction: discord.Interaction, member: discord.Member):
channel = interaction.channel
if not isinstance(channel, discord.TextChannel):
await interaction.response.send_message("请在文字频道里使用!", ephemeral=True)
return
await interaction.response.defer(ephemeral=True)
invite = await channel.create_invite(max_age=3600, max_uses=1, unique=True,
reason=f"{member} 专属邀请")
# discord.py 2.7.1 还没有对应的方法,所以直接调用端点
route = Route("PUT", "/invites/{code}/target-users/{user_id}",
code=invite.code, user_id=member.id)
await bot.http.request(route) # 成功时返回 204(无响应体)
await interaction.followup.send(
f"已创建 {member.mention} 专属邀请链接(1 小时,1 次):{invite.url}", ephemeral=True
)
# ⑤ 9/17·9/22 - 自定义状态可能看不到
@bot.tree.command(name="상태보기", description="读取成员的自定义状态(可能看不到)")
async def show_status(interaction: discord.Interaction, member: discord.Member):
custom = next((a for a in member.activities if isinstance(a, discord.CustomActivity)), None)
if custom is None:
text = "没有设置自定义状态,或者因为资料隐私设置,机器人看不到。"
else:
text = f"{custom.emoji or ''} {custom.name or ''}".strip() or "(只有表情的状态)"
await interaction.response.send_message(f"{member.display_name}: {text}", ephemeral=True)
# ⑥ 9/15 - 大型机器人分片应用必须带 shard 查询参数
async def fetch_all_guilds_by_shard(client: discord.Client) -> list:
"""给使用大型机器人分片的应用用。普通机器人直接用 client.fetch_guilds() 就行。"""
_, _, start_limit = await client.http.get_bot_gateway()
max_concurrency = start_limit["max_concurrency"]
guilds = []
for shard in range(max_concurrency):
route = Route("GET", "/users/@me/guilds")
data = await client.http.request(route, params={"shard": shard, "limit": 200})
guilds.extend(data)
return guilds
bot.run(TOKEN)💡 如果你在用第 19 篇的 cogs/ 结构,只把命令部分拆出来移到 cogs/sept_check.py,也一样能运行。
📌 运行结果
python sept_check.py机器人启动后,在服务器里逐个输入命令试试。所有回复都是仅自己可见(ephemeral)的,不会把测试服务器弄乱。

/파일한도 在没有助力的服务器上,像上面那样两个数字不同才是正常的。上面一行(20 MiB)是真正的上限,下面一行(10 MiB)说明库里的表已经过时了。

/여러줄 请在输入框里按 Shift+Enter 换行试试。机器人会数出行数,加上编号发回来。
/초대대상 要用不在目标名单里的账号打开链接,才能真正确认。不是目标的话,应该会被禁止加入。

⚠️ 老实说,本文的代码只在 Python 3.13 上做了语法·import 检查和 Route 地址拼接的确认,并没有在真实服务器上运行过命令。尤其是 /초대대상,用的是 9/18 新出的端点,请务必确认实际响应。如果不行,请不要留评论,而是通过联系页面告诉我,我会修改文章。
📌 常见错误
1. discord.errors.Forbidden: 403 Forbidden (error code: 50013): Missing Permissions — /정리예상
- 原因:服务器开启了
PRUNE_REQUIRES_ADMIN,但机器人没有管理员权限;或者在没开启的服务器上,缺少踢出成员·管理服务器权限。 - 解决:像上面的代码那样,先查看
guild.features再提示所需权限。给机器人的身份组授予所需权限后再试一次。
2. discord.errors.Forbidden: 403 — /초대대상 的 PUT 请求
- 原因:指定目标用户需要是邀请的创建者,或者拥有管理服务器权限。如果填的是别人创建的邀请码,或者机器人没有创建邀请(Create Invite)权限,就会失败。
- 解决:像示例那样只给机器人自己创建的邀请添加目标,或者给机器人的身份组授予管理服务器权限。
3. discord.errors.HTTPException: 400 Bad Request — GET /users/@me/guilds
- 原因:大型机器人分片应用在没有
shard查询参数的情况下请求了服务器列表。从 9/15 起会返回 400。 - 解决:像
fetch_all_guilds_by_shard()那样加上params={"shard": n},从0遍历到max_concurrency - 1。普通机器人不会遇到这个错误。
4. /상태보기 总是只显示"没有设置自定义状态,或者..."
- 原因:没有写
intents.presences = True,或者没有在开发者门户里开启 Presence Intent。这样member.activities永远是空元组。 - 解决:代码和门户都开启后重启机器人。两边都开了还是看不到,那就是该用户设置了资料隐私(9/17),机器人看不到。这是正常的。
5. 发送文件时出现 413 Payload Too Large / Request entity too large
- 原因:20 MiB 是没有助力的服务器的默认值。更大的文件依然不行,而且把 MB(1,000,000)和 MiB(1,048,576)混着算的话,在临界值附近会被拒。
- 解决:发送前用
os.path.getsize()和interaction.filesize_limit比较。如果用guild.filesize_limit(2.7.1 中为 10 MiB)来比较,会把能发的文件也拒掉,所以别用它。
6. /초대대상 出现 discord.errors.NotFound: 404 (error code: 10062): Unknown interaction
- 原因:没能在 3 秒内响应。要发两次 HTTP 请求,可能会比较慢。
- 解决:在耗时操作之前先调用
await interaction.response.defer(),之后用interaction.followup.send()发送。
💬 今天一定要记住的 3 件事
- 要改的只有两处。 大型机器人分片应用的
shard查询参数,成员清理机器人的PRUNE_REQUIRES_ADMIN权限检查。其余的知道就行。 - 文件上限看
interaction.filesize_limit。 库里的表(guild.filesize_limit)还停留在过时的 10 MiB。 - 字符串选项里会出现换行。 用
splitlines()接收,必须是一行的地方压成一行再用。自定义状态也变成了"看不到"才是正常情况。
📌 结语
今天没有做新功能,而是一次性过了一遍 9 月整整一个月的 Discord API 变更 🗞️
总结一下:文件上限放宽到了 20 MiB(别相信库里的值),斜杠命令的字符串开始可以多行输入,还新增了把邀请链接做成特定用户专属的端点。因为年龄验证和资料隐私,看不到自定义状态的情况变多了;大型机器人分片应用要处理 shard 查询参数,成员清理机器人要注意 PRUNE_REQUIRES_ADMIN。discord.py 2.7.1 从 3 月之后就没有新版本,所以新端点都用 Route 直接调用的方法补上了 ✅
还有别忘了,11 月 16 日的频道混淆才是最大的变更。如果还没跑过第 24 篇里的 /채널점검,这个周末一定要跑一遍 💣
Discord 机器人开发系列继 #33 派对房间之后,下一篇预计会讲用 Docker 部署机器人(计划中)。敬请期待!🙌
