更新日志
3.10.6
发布日期:2026-08-25
不兼容变更
控制面
-
自定义插件改为按网关组管理
升级说明自定义插件此前是控制面级资源,一份代码全局共用,因此为预发布环境上传一个新构建会立刻同时生效到该插件绑定的所有网关组。现在它归属于单个网关组,接口、权限以及升级后的现有部署形态都随之变化。
接口从
/api/custom_plugins迁移到/api/gateway_groups/{gateway_group_id}/custom_plugins,旧路径的所有方法都返回HTTP 410,并在消息中给出替代路径。PUT按插件名做「创建或替换」,因此流水线一次调用即可上传,且只写入自己的网关组。请求和响应体中不再有gateway_groups,改为携带gateway_group_id。GET /api/plugins现在必须带gateway_group_id查询参数,因为插件目录已经是按网关组给出的结果。权限随资源一起迁移,从
arn:api7:gateway:gatewaysetting/*变为arn:api7:gateway:gatewaygroup/{gateway_group_id}。gateway:CreateCustomPlugin不再存在——上传是同一个端点上的「创建或替换」,由gateway:UpdateCustomPlugin覆盖——读取自定义插件则需要新增的gateway:GetCustomPlugin权限。此前读取不需要任何权限,任何已登录用户都能读到任意自定义插件的源码;升级后,从未被授予自定义插件权限的角色无法列出或读取它们,需要额外授予gateway:GetCustomPlugin。升级程序会改写已存储的策略:原本在旧资源上授予自定义插件动作的语句保留其余动作,自定义插件相关动作迁移到arn:api7:gateway:gatewaygroup/*上的新语句,效果与条件不变,其中gateway:CreateCustomPlugin被改写,并补上gateway:GetCustomPlugin。被替换的策略文档保存在permission_policy_backup中。同一个升级程序会把每个已有插件展开成它曾部署到的每个网关组各一条记录,因此插件在升级后无需任何操作即可继续工作。升级后有两种情况需要留意:未部署到任何网关组的插件没有归属,会被记录到日志而不迁移,需要手动上传到需要它的网关组;此前路由可以引用一个从未部署到其所在网关组的插件,控制面接受该配 置而数据面忽略它,因此插件从未真正运行过,升级后该网关组没有这个插件,下一次写入该路由时会报告插件未知,直到移除这段失效的插件配置。
最后请注意,在 3.10.6 上上传的插件代码只存在于新表中,因此回滚到更早的版本会使用升级前的旧表中保存的代码。
升级须知
$http_x_forwarded_* 现在记录的是客户端发送的值对于来自不受信任对端的请求,网关一直会覆盖 X-Forwarded-Proto、X-Forwarded-Host 和 X-Forwarded-Port 并清除 Forwarded。这部分工作现在由 NGINX 配置完成,不再由 Lua 执行。上游收到的内容没有变化,插件看到的也没有变化:core.request.header 与 ctx.var.http_x_forwarded_* 返回的仍是覆盖后的值,ctx.var.original_x_forwarded_* 返回的仍是客户端发送的值。
不同的是 NGINX 配置层。在访问日志格式、if 或 map 中引用 $http_x_forwarded_proto、$http_x_forwarded_host、$http_x_forwarded_port 或 $http_forwarded 时,现在读到的是客户端发送的值,而此前读到的是覆盖后的值。因此,用 $http_x_forwarded_host 记录审计日志的格式会开始记录由客户端控制的值:伪造 X-Forwarded-Host: evil.example.com 的请求在升级前记录的是真实 host,升级后记录的是 evil.example.com。
如需记录覆盖后的值,请改用 $scheme、$var_x_forwarded_host 和 $var_x_forwarded_port。$http_x_forwarded_for 不受影响。客户端发送的值也可以通过新增的 $original_x_forwarded_proto、$original_x_forwarded_host、$original_x_forwarded_port、$original_x_forwarded_for 和 $original_forwarded 这几个 NGINX 变量读取。
除非在插件元数据中设置了 max_pending_entries,所有日志插件背后的批处理器都会把未投递的条目无上限地保留在 worker 内存中,因此日志服务器变慢或不可达时,worker 内存会随请求速率一起增长。该上限现在默认为 8192 条,同时 datadog、lago、loggly、sls-logger 以及 stream 子系统的 syslog 首次暴露该配置项。
日志服务器能正常消费的部署不受影响:待处理量取决于 batch_max_size 而 不是请求速率,通常远低于一千条。达到上限后,新条目会被丢弃,并以每秒至多一条日志的频率报告累计丢弃数。如果你记录了大于几 KB 的请求体或响应体,请在插件元数据中调低 max_pending_entries,使待处理量符合你的内存预算;如果调高过 batch_max_size,也应同步调高该值。
OpenID Connect 上可配置的三项校验此前并非在所有情况下都生效,导致本应被拒绝的请求被放行。现在这些配置会被真正执行,此前能通过的流量可能开始收到 HTTP 401 或 403。
required_scopes 此前只作用于通过内省校验的令牌。使用授权码流程的路由(即未设置 bearer_only 的默认形态)从不读取会话被授予的 scope,因此任何完成登录的用户都会被放行。现在 scope 会从 access token 中读取,无法确定所授予 scope 的会话会被拒绝而不是放行。在授权码流程中依赖 required_scopes 之前,请确认你的身份提供方签发的 access token 是携带 scope 的 JWT,或者 ID token 中携带该字段。
claim_validator.audience.match_with_client_id 此前只在 aud 声明存在时才与 client id 比对,因此不带 aud 的令牌会跳过该校验。现在该选项隐含要求该声明必须存在,不带 aud 的令牌会收到 HTTP 403。
在 bearer_only 模式下且未配置 valid_issuers 时,受信任的 issuer 来自提供方的 discovery 文档;此前该请求失败时网关只记录一条 warning,并在完全没有 issuer 约束的情况下校验令牌。现在会返回 HTTP 401,并携带 error_description="issuer validation unavailable"。如果不希望请求路径依赖 discovery 端点的可用性,请显式配置 valid_issuers。
AI Proxy Multi 此前接受两个 name 相同的 instance,这会让请求实际路由到哪个 instance 变得不确定。此类配置现在在写入时就以 HTTP 400 拒绝。
已经存储的配置仍可继续工作,但升级后会在数据面的配置兼容性报告中以 error 级别出现。请重命名重复的 instance 使每个名字唯一,配置被重新写入后该报告项即消失。
LDAP Auth 此前通过普通字符串拼接重建一个可分辨名称(DN)来查找消费者,而只要用户名中含有在 DN 中具有结构含义的字符(, + = < > ; " \),这个 DN 就与实际用于绑定的 DN 不同。现在改为使用绑定时生成的转义 DN。
目录中所有用户名都不含上述字符的部署不受影响。如果某个消费者的 user_dn 是按旧行为以未转义形式写入的,请改写为 RFC 4514 转义形式(例如 cn=comma\,user,ou=users,dc=example,dc=org),否则该消费者在升级后不再匹配。
为修复下文「缺陷修复」中描述的变体键碰撞问题,Proxy Cache 在 memory 策略下的存储键布局发生了变化,缓存版本号也随之提升。因此旧版本写入的条目在新布局下不可达:每个键的第一次请求为 MISS 并重新填充缓存,而对只有升级前条目的 URL 执行 PURGE 会返回 HTTP 404。旧条目会一直留在共享内存中,直到各自的 TTL 到期。使用默认 disk 策略的部署不受影响。
新功能
插件
- GraphQL Limit Count
- 新增按查询成本限流的能力,使一个 GraphQL 请求按其请求的工作量消耗配额,而不是一律计为一次请求。
cost_strategy选择成本的计算方式——depth按选择集的嵌套深度计算,complexity按查询解析的节点数计算,node_quantifier按参数要求每个字段返回的对象数量计算——score_factor对结果进行缩放。设置max_cost后,超过该成本的查询在到达上游之前即以HTTP 403拒绝,计算出的成本通过X-Graphql-Query-Cost响应头返回。当服务上配置了成本装饰时,需要内省上游 schema 才能与之匹配,该内省按服务执行一次,端点由introspection_endpoint指定,introspection_headers携带该端点所需的凭据。启用resolve_variables后,通过 GraphQL 变量传入的参数会参与成本计算,而不是被当作未提供。
- 新增按查询成本限流的能力,使一个 GraphQL 请求按其请求的工作量消耗配额,而不是一律计为一次请求。
- Prometheus
- 新增三个四层流量指标,与原本就已导出的
apisix_stream_connection_total计数器并列:按终止状态、监听地址和上游节点统计已结束会话的apisix_stream_status,按监听地址反映当前 TCP 连接与 UDP 会话数的apisix_stream_active_connections,以及按监听地址、方向和连接侧统计代理字节数的apisix_stream_bandwidth。采集这些指标需要在 stream 路由上启用该插件。插件元数据的disabled_labels现在支持stream_status键,用于关闭apisix_stream_status上的标签,与status对 HTTP 计数器的作用相同。
- 新增三个四层流量指标,与原本就已导出的
- AI Proxy Multi
- 新增
fallback_http_statuses,用于列出哪些上游 HTTP 状态码会让网关把请求重试到下一个 instance。此前只有在完全无法连接某个 instance 时才会回退,因此提供方因密钥过期返回401、或因该账号配额耗尽返回429时,这些响应会直接返回给客户端,而不会转由其他 instance 重试。
- 新增
- LDAP Auth 与 LDAP Auth Advanced
- 两个插件都新增
hide_credentials,在客户端通过认证后移除Authorization请求头,使目录凭据不会被转发到上游。默认值为false,与此前行为一致。
- 两个插件都新增
控制面
- 自定义插件现在归属于单个网关组而不是整个部署,因此同一个插件名可以在预发布和生产环境运行不同的代码,向一个环境上传也不会影响其他环境。接口、权限与迁移细节参见「不兼容变更」。
- GraphQL 查询成本现在可以通过服务上新增的
graphql_cost_decorations子资源按服务调整。一条装饰指定一个字段路径(如Query.products或Product)并调整该字段对成本的贡献:既可以是固定的add_value,也可以按mul_arguments中列出的参数值对其子节点做乘法——例如返回first: 10个对象的字段按十倍计价。装饰会针对其所属服务做校验,同一个字段路径只能被装饰一次,且改动无需触碰承载该插件的路由即可下发到数据面。 - 路由现在可以匹配
PURGE方法,Proxy Cache 和 GraphQL Proxy Cache 正是用它来失效缓存条目的。网关一直接受该方法,只有控制台自身的 schema 拒绝它,因此此前无法通过接口或控制台创建用于缓存失效的路由。 - 上游与路由的超时现在接受小数秒,可以配置
0.5,而此前接口要求整数。数据面一直支持亚秒级超时。最小值为0.001,因为低于一毫秒的部分会被截断。
数据面
- 请求携带的
X-Forwarded-*请求头改由 NGINX 配置消毒,不再由 Lua 在每个请求上处理。插件看到的值与此前一致,而客户端发送 的原始值——在 Lua 中一直可以通过ctx.var.original_x_forwarded_*读取——现在也成为 NGINX 变量,可以写进日志格式。唯一发生变化的记录位置参见「升级须知」。
控制台(Dashboard)
- 新增繁体中文(台湾)与越南语。中文的语言标签现在明确区分是哪一种中文——
zh-Hans-CN与zh-Hant-TW——因此缺失的繁体文案会明显地回退到英文,而不是静默显示简体文案。此前已选择中文的用户,语言设置保持不变。 - License 页面现在把部署 ID(Deployment ID)作为许可证表格的第一行展示,并带复制按钮。部署 ID 是申请签发或续期许可证时需要提供给 API7 的信息,此前只出现在「更新 License」对话框中,而该对话框受更新许可证权限限制,没有该权限的用户根本无法读到它。即使尚未激活许可证,该行也会显示。
开发者门户
- 门户前端已在 TanStack Start 上重建,取代原有的 Next.js 应用。部署方式没有变化——同一个镜像、同一个端口、同一份
config.yaml——因此升级无需修改任何配置。 - 尚未被接受的组织邀请现在可以在成员页面重新发送,而不必先撤销再重新签发。
- 当只配置了一个身份提供商时,登录页会自动选中它,而不是让开发者从只有一项 的列表中选择。
- 顶栏中的组织头像与个人头像现在有明显区分,便于确认当前处于哪个组织的上下文中。
- 组织标识字段的名称从 “URL” 改为 “Slug”,与该值的实际含义一致。
缺陷修复
插件
- GraphQL Limit Count
- 修复问题:当 GraphQL 文档中的片段相互展开时,每次被引用都会重新展开一次,因此很小的请求体也可能消耗不受限的 CPU。一个含 34 层链式片段的 1.4 KB 文档可以让 worker 满载运行超过 45 秒,期间网关在所有路由上都不返回任何响应,必须重启才能恢复。现在每个片段只计算一次,片段展开形成环的文档会以
HTTP 400拒绝。
- 修复问题:当 GraphQL 文档中的片段相互展开时,每次被引用都会重新展开一次,因此很小的请求体也可能消耗不受限的 CPU。一个含 34 层链式片段的 1.4 KB 文档可以让 worker 满载运行超过 45 秒,期间网关在所有路由上都不返回任何响应,必须重启才能恢复。现在每个片段只计算一次,片段展开形成环的文档会以
- AI Proxy
- 修复问题:当流式上游返回
HTTP 200和Content-Type: text/event-stream后不写入任何内容就结束响应时,请求既没有被应答也没有被终止,客户端因此完全收不到 HTTP 响应,访问日志记录为长度为零的500。现在返回HTTP 502。
- 修复问题:当流式上游返回
- AI Proxy Multi
- 修复问题:请求重试到下一个 instance 时,使用的是上一次尝试已经改写过的请求体,因此上一个 instance 的
options(例如temperature或max_tokens)会泄漏到发往回退 instance 的请求中,模型名也可能被覆盖。现在每次尝试都从客户端自己的请求体开始构建。
- 修复问题:请求重试到下一个 instance 时,使用的是上一次尝试已经改写过的请求体,因此上一个 instance 的
- Redirect
- 修复问题:启用
http_to_https时,X-Forwarded-Proto请求头以大小写敏感的方式比较,因此发送HTTPS的客户端或负载均衡器会被重定向到它已经访问到的 HTTPS 地址,形成重定向环。现在改为大小写不敏感比较。
- 修复问题:启用
- Data Mask
- 修复问题:对于由网关自身应答而不是转发到上游的请求——例如被认证插件、限流或 Fault Injection 拒绝的请求——请求头脱敏不生效。随后运行的日志插件读取的是未经修改的请求,因此本应被脱敏的凭据以明文形式发送到了日志接收端。现在脱敏在所有路径上都生效。
- 修复问题:从 JSON 数组中删除一个元素后会留下空洞而不是压实数组,导致被删元素之后的元素在记录的请求体中丢失:对
["a","b","c"]脱敏$.items[1]记录出的是["a"]而不是["a","c"]。
- Proxy Cache
- 修复问题:在
memory策略下,Vary变体的存储键是缓存键加上变体签名,而缓存键由请求 URI 推导得出。因此一个把他人变体签名构造进自身 URI 的请求会得到相同的存储键,于是读到了该请求缓存的响应,并且它自己的 响应会被写入下一个请求查找该变体的位置。现在存储键的推导方式保证任何构造出的请求都无法重现另一个请求的键。升级前已缓存条目的影响参见「升级须知」。
- 修复问题:在
- OpenID Connect
- 修复问题:身份提供方带
error=temporarily_unavailable回跳时(规范将其定义为临时性状况),网关返回HTTP 500。现在会从原始 URL 重新发起认证流程,同一会话最多重试三次,而access_denied等其他错误码仍按最终结果处理。 - 修复问题:
required_scopes、claim_validator.audience.match_with_client_id以及 issuer 校验并非在所有情况下都生效,导致本应被配置拒绝的请求被放行。参见「升级须知」。
- 修复问题:身份提供方带
- LDAP Auth
- 修复问题:查找消费者时使用的是字符串拼接重建的可分辨名称,而不是插件实际用于绑定的转义 DN,因此名称中含 DN 元字符的目录条目虽然认证成功,却匹配不到消费者,或匹配到属于另一个条目的消费者。参见「升级须知」。
- HMAC Auth
- 修复问题:启用
hide_credentials时,Authorization请求头虽然从发往上游的请求中移除了,却仍留在缓存的请求头中,因此同一路由上排在 HMAC Auth 之后的插件仍能读到该签名凭据。
- 修复问题:启用
- AWS Lambda
- 修复问题:以
Transfer-Encoding: chunked发送的请求体在转发给函数时未重新分帧,导致调用失 败,客户端收到HTTP 503,错误日志中出现failed to process aws-lambda, err: closed。现在转发时会携带Content-Length。共用该代码路径的其他 serverless 上游插件同样适用。
- 修复问题:以
数据面
- 修复问题:解析作为 CNAME 的上游主机时,只有当应答的最后一条记录恰好是所请求的类型时,解析结果才会被折叠到被查询的名字上。解析器附加 EDNS(0) OPT 记录、或应答段未按链的顺序返回,都会使这一判断失效,于是解析到的记录被记在规范名而不是被查询的名字下——并且一条属于无关名字的同类型记录可能被改记到被查询的名字上并缓存。现在会沿链走到它最终指向的名字,只折叠该名字拥有的记录。
控制面
- 修复问题:任何已登录用户都能列出某个服务的上游(包括节点地址),因为列出上游的端点没有任何权限校验,而同一份数据的其他视图都按权限过滤。现在列出服务的上游需要该服务的查看权限。
- 修复问题:更新 CA 证书或客户端证书后,引用它的上游只有在是服务的默认上游时才会重新下发,因此非默认上游会一直使用旧证书,直到被手动编辑一次。
- 修复问题:为同一个 SNI 同时配置
cert/key和certs/keys的 SSL 配置(即 RSA 与 ECDSA 证书并存的常见 形态)会被以input matches more than one oneOf schemas拒绝。现在两者可以一起使用,数据面会按客户端偏好协商相应的证书。 - 修复问题:使用非对称算法的
jwt-auth消费者凭据在写入配置存储时会带上一个用户从未配置过的占位private_key字段,数据面将其报告为无法识别的字段,且该字段以明文存储。现在不再添加该字段。升级前写入的凭据会保留该字段,直到下一次被保存。
控制台(Dashboard)
- 修复问题:在同一个页面会话中重复打开 YAML 模式的插件编辑器,会使补全列表中的每个字段按打开次数重复,打开五次后每个字段出现五次。现在编辑器的 YAML 支持在每个页面只配置一次。
开发者门户
- 修复问题:访问不存在的组织、或开发者不属于的组织时,只弹出一个错误提示,而没有说明发生了什么的页面。
- 修复问题:邀请链接和落地页在开发者接受邀请后,可能把已登录的开发者跳转到错误的位置。
- 修复问题:文档中的 “Copy page” 按钮换行到了第二行,而不是与页面标题的第一行对齐。
3.10.5
发布日期:2026-08-11
不兼容变更
插件
-
升级说明
该插件现在会校验日志服务器的 TLS 证书。旧版本在完成 TLS 握手时完全不校验证书,因此日志服务器出示自签名证书、私有 CA 签发的证书或已过期的证书都会被静默接受,而携带所配置访问密钥的日志记录仍会发往该服务器。
校验行为由新增的
ssl_verify选项控制,默认值为true。升级后,若网关无法校验日志服务器的证书,批处理器会丢弃这批日志,并在错误日志中记录failed to perform TLS handshake to TCP server。如果你的日志服务器出示的证书并非由公共可信 CA 签发,请在升级前把签发该证书的 CA 加入数据面的可信证书库,或在插件上把ssl_verify设为false以保持 旧行为。
升级须知
headers 字段落盘加密在启用数据面数据加密(apisix.data_encryption.enable)时,控制面现在会对 Loki Logger 的 headers 字段做落盘加密。由于 API7 EE 的升级顺序是先控制面、后数据面,在升级窗口内 3.10.5 的控制面会加密该字段,而仍为 3.10.4 的数据面无法解密,可能导致该插件在数据面升级完成前无法正常工作。
如果你使用了 Loki Logger 的 headers,请在控制面升级后尽快把数据面也升级到 3.10.5,并在两侧都升级完成前避免编辑该插件。
控制台会话 Cookie 的签名密钥此前是编译期常量,所有部署完全相同。现在改为首次启动时生成的 32 字节随机密钥,并按部署持久化保存,因此会话 Cookie 不再可能用一个各处相同的值签发。
升级前签发的会话使用的是旧的常量密钥,升级后不再被接受。控制面升级完成后,所有已登录用户都需要重新登录一次。升级前无需做任何准备,也不需要修改配置。
radixtree_host_uri 路由器Docker Compose 部署包现在会把 apisix.router.http 设为 radixtree_host_uri,与 Helm Chart 一直使用的默认值保持一致。此前该部署包不设置这一项,回落到 radixtree_uri,因此同一份配置在不同部署形态下的路由匹配结果可能不同。
仅依赖普通 host 与路径匹配的配置不受影响。差异出现在「指定了 host 的路由」与「未指定 host 的路由」共享重叠路径时:radixtree_host_uri 会先查按 host 划分的子路由器,只有都未命中时才回落到未指定 host 的路由;而 radixtree_uri 把所有路由放在同一棵树中,按路径特异性与 priority 排序。如需保留旧的匹配引擎,可在 gateway_conf/config.yaml 中把 apisix.router.http 设为 radixtree_uri。
控制台现在在浏览器端应用界面语言,并用 Cookie 记住所选语言,因此 URL 不再带 /zh 前缀。升级后,含 /zh 的书签和已保存的链接会返回 HTTP 404,去掉该前缀后的同一路径即可访问对应页面。可选语言以及语言切换器本身没有变化。
新功能
插件
- LDAP Auth Advanced
- 新增该插件,用于对接 LDAP 目录完成客户端认证,并把认证结果映射到消费者。插件采用「先检索、后绑定」的方式解析用户:在
base_dn下按attribute=username检索,再以检索到的条目执行绑定,因此无需把目录结构写进网关配置。凭据从Authorization请求头读取,支持ldap和basic两种方案(header_type
- 新增该插件,用于对接 LDAP 目录完成客户端认证,并把认证结果映射到消费者。插件采用「先检索、后绑定」的方式解析用户:在