更新日志
3.10.10
发布日期:2026-11-11
不兼容变更
插件
-
升级说明
header_prefix现在配置在使用该插件的路由或服务上(包括在 Multi Auth 中配置的 Wolf RBAC),消费者上不再支持该字段。消费者上的appid现在为必填:此前不带appid的消费者也能保存,并匹配为应用 IDunset签发的 Token。网关升级后,会丢弃 Wolf RBAC 配置中header_prefix不是默认值X-的消费者(日志为header_prefix is no longer supported in consumer configuration),以及未设置appid的消费者(日志为property "appid" is required)。使用这些消费者 Token 的请求随后会认证失败,返回HTTP 401。控制面升级时不会转换这些消费者,重新保存它们会被拒绝,返回HTTP 400。升级前,请把每个自定义的
header_prefix从消费者移到所有使用 Wolf RBAC 的路由或服务上,并从消费者中删除;同时为所有未设置appid的消费者设置appid,依赖此前默认值的消费者设置为unset即可继续接受原来的 Token。header_prefix为X-的消费者无需修改。尚未升级的网关实例只从消费者读取header_prefix,会忽略路由或服务上的该字段,因此从自定义header_prefix从消费者中删除起,到网关组的所有实例完成升级为止,这些实例会以默认前缀X-命名身份请求头。
升级须知
SNI 的 ssl_protocols 中保存的 TLS 协议版本此前从未下发到网关,因此无论保存的是什么,每个 SNI 接受的都是网关全局配置 apisix.ssl.ssl_protocols 中的版本:限制为 TLSv1.3 的 SNI 仍能完成 TLS 1.2 握手。/apisix/admin/ssls API 会忽略该字段,在其写入的每个 SNI 上都保存 TLSv1.2 和 TLSv1.3,响应中也不返回该字段。现在两个 API 都会下发该设置,网关也会执行它。SNI 的协议版本会替换网关全局配置,而不是在其基础上收窄,因此 SNI 也可以放开全局配置不允许的版本。未设置 ssl_protocols 的 SNI 跟随全局配置;SNI API 在请求不带该字段时不再自动填入 TLSv1.2 和 TLSv1.3,未设置时两个 API 的响应中都不包含该字段。此前可以保存的 [] 和包含重复版本的列表,现在会被拒绝,返回 HTTP 400。
升级控制面时,控制面会把保存为 [],或只含 TLSv1.2 和 TLSv1.3(顺序不限,含重复项)的 SNI 的 ssl_protocols 清空,使这些 SNI 继续跟随全局配置,并去掉其他列表中重复的版本。其余保存了列表的 SNI 会立即下发到网关并从此开始 生效,尚未升级的网关实例同样会执行。升级前,请检查保存了其他列表(例如只有 TLSv1.3)的 SNI:使用列表之外的版本连接这些 SNI 的客户端将无法完成 TLS 握手。
在 Dashboard 中,未设置 ssl_protocols 的 SNI(升级后大多数存量 SNI 都属于这种情况)的编辑表单必须选择协议才能保存,保存后所选列表会写入该 SNI,它从此不再跟随全局配置。如需修改这样的 SNI 并让它继续跟随全局配置,请通过 API 更新,且不要带 ssl_protocols。Dashboard 的创建表单同样要求选择协议(默认为 TLSv1.2 和 TLSv1.3),因此在 Dashboard 中创建的 SNI 会保存一个显式列表;如需让其跟随全局配置,请通过 API 创建,且不要带 ssl_protocols。
控制面现在会拒绝一些此前接受的 JSON Web Key,且只要有一个 Key 被拒绝,整个 Key Set 都无法使用:
- 身份提供方在
jwks_uri发布的 Key Set 中含有模数超过 4096 位或指数e超出范围的 RSA Key,或者是低阶点的 Ed25519 Key 时,通过 OpenID Connect 进行的 SSO 登录会失败,无论身份提供方是否用该 Key 签名。 - API Usage 服务以
jwks.enable: true运行时(默认关闭),如果jwks.url处的 Key Set 含有上述 Key、长度不是 32 字节的 Ed25519 Key,或含有以带=填充的 base64url 编码的成员,该服务会以HTTP 401拒绝所有携带 Token 的请求。
升级前,请检查 SSO 所用的每个 OpenID Connect 身份提供方 jwks_uri 处的 Key Set;如果 API Usage 服务启用了 JWKS,还要检查 jwks.url 处的 Key Set,确认两者都不含上述 Key。
控制面镜像现在基于 Debian 13 构建,其 CA 证书包中不再包含 emSign ECC Root CA - G3 和 AAA Certificate Services 两个根证书。控制面发起的 TLS 连接(例如连接身份提供方、SMTP 服务器或 Webhook)在服务器证书只能链到这两个根证书之一时,现在会证书校验失败。posix/ 下的时区名称也不再提供,使用此类名称的 TZ 设置或数据库时区需要改为去掉该前缀的名称。网关镜像不受影响。
Token 内省失败时,OpenID Connect 插件现在返回不带 WWW-Authenticate 质询的 HTTP 503,而不是带 invalid_token 质询的 HTTP 401。这包括内省端点返回错误状态码、超时或无法连接,以及响应不是 JSON、active 声明缺失或不是布尔值的情况。只有身份提供方报告 Token 无效时,才返回带 invalid_token 的 HTTP 401。把所有 HTTP 401 都当作需要重新获取 Token 的客户端,在身份提供方不可用时现在会收到 HTTP 503。
active 声明为字符串(例如 "true")的响应此前会被当作有效,请求会被转发。这样的响应现在会被拒绝。如果你的身份提供方以字符串返回 active,请在升级前修正。
Forward Auth 插件现在通过另一个 HTTP 客户端向授权服务发送请求,每个请求消耗的 CPU 更少。授权服务可能会注意到以下差异:
- 不再发送
User-Agent请求头,此前为lua-resty-http/<version>。 GET请求带有Content-Length: 0。- 会发送
Connection: keep-alive,keepalive为false时也是如此,此时连接仍会在请求结束后关闭。 - 通过
extra_headers设置的空Host会被替换为网关连接的地址。 timeout限制的是读取整个响应的时间,而不是每次读取的时间。
如需恢复此前的客户端,请在网关配置文件中把 plugin_attr.forward-auth.http_client 设为 lua-resty-http;默认值为 ngx_http_ffi_client。
last_retrieve_config_timeGET /api/instances 和 GET /api/gateway_groups/{gateway_group_id}/instances 不再返回 last_retrieve_config_time。该字段记录的是网关实例发起配置请求的时间,而不是收到配置的时间,也没有任何产品功能使用它。如需判断实例是否在线,请使用 last_heartbeat_time。
请在网关组的所有网关实例都升级到 3.10.10 之后,再配置 OpenID Connect 插件的 upstream_headers。较早版本的网关实例会忽略该字段,既不会设置这些请求头,也会把客户端以相同名称发送的请求头原样转发给上游。
新功能
插件
- OpenID Connect
- 新增
upstream_headers选项,可以把已验证 Token 中选定的声明作为请求头转发给上游,不解析 Token 的上游不再需要通过 Serverless 函数再次解码 Token。每一项指定一个请求头以及指向声明的键路径,每一层嵌套对应一个键,因此包含/、.或://的声明名称可以直接使用。声明取自已验证的 Token 或内省响应;在授权码流程中先取自 ID Token,ID Token 中没有的声明再取自用户信息。字符串原样转发,数字和true以文本转发,数组和对象以 base64 编码的 JSON 转发;空数组或空对象以 base64 编码的{}转发;声明缺失、为null或false时不设置请求头。无论认证 结果如何(包括以unauth_action: pass放行的未认证请求),所列的每个请求头都会先从请求中移除,因此它要么是已验证的声明,要么不存在。
- 新增
- Wolf RBAC
header_prefix现在可以在路由或服务上设置,路由的身份请求头不再取决于 Token 匹配到的消费者。参见上文的升级说明。
控制面
- 现在可以要求内置用户定期修改密码,并禁止重复使用最近用过的密码。在 Dashboard 中,该策略位于 Organization > Settings > Login Options > Password Policy,也可以通过
/api/system_settings/password_policy管理。password_max_age_days设置密码最长有效期,取值 1 到 365 天;0(默认值)表示关闭策略。password_history_count取值 0 到 24,默认 5,设置策略开启时用户修改自己的密码不能重复使用的历史密码个数;0表示只拒绝当前密码。管理员重置的密码不检查历史。密码超过最长有效期后,用户仍可以登录,但必须先修改密码才能进行其他操作:用该用户的会话或 Basic Auth 发起的其他请求都返回HTTP 401和password expired,Dashboard 会要求输入新密码。访问令牌和 SSO 用户不受约束。GET /api/me在password_expires_at中返回到期时间。升级控制面时,所有存量密码的有效期从升级时刻开始计算,因此升级后开启策略不会立即锁住任何用户。 - 现在可以要求所有内置用户(包括
admin)启用双因素认证,开关位于 Dashboard 的 Organization > Settings > Login Options,也可以通过/api/system_settings/two_factor_policy设置。该开关默认关闭,内置用户只有在为自己的账号启用双因素认证后才能打开它。开关打开时,未启用双因素认证的内置用户仍可以用密码登录,但登录后只能启用双因素认证(Dashboard 会引导完成)或退出登录,其他请求都返回HTTP 401和two factor enrollment required。这类用户的 Basic Auth 请求也会以同样的方式被拒绝;已启用双因素认证的用户的 Basic Auth 本来就会被拒绝,因此 Basic Auth 对所有内置用户都不再可用。访问令牌、Admin API Key 和 SSO 会话不受该开关约束。内置用户(包括admin)同时丢失验证器和恢复码时,可以在 Dashboard 容器中(例如通过kubectl exec或docker exec)运行/usr/local/api7/api7-ee-dashboard two-factor reset --username <name>恢复;配置文件不在/app/conf/config.yaml时(例如 Docker Compose 部署)需加上-c <配置文件>,即-c /usr/local/api7/conf/conf.yaml。该命令会清除该用户的双因素认证并使其会话失效。 - 现在未激活有效 License 时,用户也可以为自己的账号设置并启用双因素认证。此前这些请求会返回
HTTP 404或HTTP 400,需要启用双因素认证的用户在上传 License 之前无法完成启用。 - 现在不指定网关组也可以读取内置插件目录和内置插件的 Schema。
GET /api/plugins、GET /apisix/admin/plugins/list和GET /apisix/admin/plugins/{plugin_name}不带gateway_group_id时返回内 置插件;带上该参数或使用网关组的 Admin API Key 时,与此前一样返回内置插件和该网关组的自定义插件。GET /api/plugins此前不带gateway_group_id时返回HTTP 400。GET /apisix/admin/plugins/list上取值为空的gateway_group_id=参数现在会被拒绝,返回HTTP 400。 - Docker Compose 安装现在也可以在 Podman 上运行,包括启用了 SELinux(Enforcing)的主机,无需手动重新标记或编写覆盖文件。Podman API Socket 未运行时,安装会在做任何改动之前停止,并打印启动它的
systemctl命令。安装脚本启动的 PostgreSQL、Prometheus 和网关容器,以及通过 Dashboard 生成的 Docker 部署命令启动的网关容器,现在都会自动重启。
数据面
- 插件现在最多读取
apisix.max_request_headers_readable个请求头,该项在网关配置文件中设置。默认值100与此前的限制相同,0表示不限制。此前 Request Validation、OPA 和 Forward Auth 等插件只能看到请求的前 100 个请求头。超出限制的请求头仍会转发给上游。 - 在使用 Forward Auth、Request ID 和 Prometheus 插件的路由上,以及
key或count中包含变量的 Limit Count 和 Limit Count Advanced 配置下,网关处理每个请求消耗的 CPU 更少。
缺陷修复
插件
- Forward Auth
- 修复问题:
allow_degradation为true时,如果无法连接授权服务,客户端以upstream_headers中所列名称发送的请求头会原样传给上游,因此客户端可以自行设置上游认为来自授权服务的值,例如用户 ID。现在这些请求头会在转发请求前被移除。
- 修复问题:
- JWE Decrypt
- 修复问题:
strict为false时,不带 Token 的请求会连同客户端发送的forward_header所指定的请求头一起转发,因此客户端可以传入上游认为是解密后 Token 的值。现在请求不带 Token 时会移除该请求头。
- 修复问题:
- Wolf RBAC
- 修复问题:在 Multi Auth 中配置了 Wolf RBAC 且由其他插件完成认证时,客户端发送的
X-UserId、X-Username和X-Nickname请求头会原样传给上游,因此客户端可以自行设置上游认为已由 Wolf 验证的身份。现在这些请求头会从每个请求中移除, 只有 Wolf 授权成功后才会设置。
- 修复问题:在 Multi Auth 中配置了 Wolf RBAC 且由其他插件完成认证时,客户端发送的
- OpenID Connect
- 修复问题:携带同一个尚未缓存的 Token 的并发请求会各自调用内省端点。现在它们共用同一次内省请求。
- Prometheus
- 修复问题:为避免为指标设置
expire时出现 CPU 峰值,3.10.8 把指标库回退到了较早的版本,这又带回了两个问题:指标所用的共享字典写满后,Worker 可能进入循环,CPU 持续 100%,流量停止后也无法恢复;该字典中的过期条目也不会被回收。现在指标库已升级到 1.1.1,修复了这两个问题,并减少了导致上述 CPU 峰值的过期条目清理工作。
- 修复问题:为避免为指标设置
- Limit Count、Limit Count Advanced、GraphQL Limit Count、AI Rate Limiting、Limit Req 和 Limit Conn
- 修复问题:使用
redis-cluster策略并设置了redis_cluster_ssl或redis_password时,出现过故障的 Redis Cluster 节点恢复后仍被标记为不健康,因为其健康检查连接时既不使用 TLS 也不带密码。计数存放在该节点上的请求会一直失败(Limit Count 返回HTTP 500),直到重启网关。
- 修复问题:使用
数据面
- 修复问题:在网关配置中启用
apisix.match_uri_encoded_slash时,请求可以通过在路径中编码斜杠,跳过启用了 mTLS 的 SNI 的客户端证书校验。skip_mtls_uri_regex的规则是针对解码后的路径检查的,而路由匹配使用的是把%2F保留在路径段内的路径,因此/public%2Fstatus这样的请求会被^/public/status$这样的规则豁免,却可能被路由到另一条路由(例如/:resource),无需客户端证书即可访问。现在只有当路径的两种形式都匹配规则时,请求才会跳过校验;不带客户端证书的此类请求会被拒绝,返回HTTP 400。 - 修复问题:
gzip插件的buffers.size小于内存页大小(大多数系统上为 4 KiB)时,压缩一个放不进单个缓冲区的响应会导致网关 Worker 崩溃,客户端收不到任何响应。 - 修复问题:请求复用一个仍在建立中的多路复用上游连接时,
dubbo-proxy插件可能返回HTTP 500。
控制面
- 修复问题:已知启用了双因素认证的用户的密码后,可以无限次尝试验证码,已被接受的验证码在其有效期内还可以再次使用,并发请求也是如此。现在连续 5 次输入错误的验证码或恢复码后,该用户的第二因素会被锁定 15 分钟,期间所有验证码(包括正确的)都会被拒绝,返回
HTTP 400和too many failed login attempts, this account is temporarily locked; please try again in about N minute(s),恢复码也不会被消耗。每次锁定都会记录到审计日志。已被接受的验证码及更早的验证码现在都会被拒绝,因此例如登录后立即关闭双因素认证需要使用下一个验证码。关闭双因素认证时输错的验证码也计入同一上限。 - 修复问题:携带无法解码的会话 Cookie(例如为空、被截断或被篡改)的请求返回
HTTP 500而不是HTTP 401,带着这样的 Cookie 登录也会失败。浏览器在修改密码后就会发回这样的 Cookie,因此 Dashboard 显示的是错误而不是登录页。现在这样的 Cookie 会被忽略:请求返回HTTP 401和user not logged in,登录也能正常完成。 - 修复问题:网关实例的每次配置请求都会同时更新数据库中该实例的记录,因此只有在持有该记录的事务(例如心跳)结束后,或者等到数据库超时(默认 5 秒)后,配置才会下发。现在配置请求不再写数据库。
- 修复问题:不指定网关组时,
GET /apisix/admin/plugins/{plugin_name}、POST /apisix/admin/configs/validate和GET /apisix/admin/plugin_metadata/{plugin_name}/default会在所有网关组中查找自定义插件,因此会返回其他网关组自定义插件的 Schema 或元数据默认值,使用该插件的配置也能通过校验。现在不指定网关组时,对自定义插件的答复与对不存在的插件完全相同。 - 修复问题:Docker Compose 安装在某一步失败时(例如
docker compose up无法启动某个服务)仍会打印API7-EE is ready!并以状态码0退出。现在会以非 0 状态码退出,并打印失败原因、docker compose ps -a以及每个服务最近的日志。以较严格的umask(例如027)解压安装包时,Dashboard 和网关无法读取各自的配置文件而无法启动;现在启动前会 把这些文件设为可读。安装包中的文件现在归root所有。由较早的安装包启动的网关容器不会自动重启,请先执行bash run.sh stop,再执行bash run.sh重新创建。
控制台(Dashboard)
- 修复问题:删除 SNI 的确认对话框中显示的是未解析的
{{name}}占位符,而不是需要输入的 SNI 名称。
3.10.9
发布日期:2026-10-29
不兼容变更
插件
-
升级说明
现在只有当 Keycloak 授予了路由请求的每个权限以及其中的每个 Scope 时,请求才会被转发。此前插件一次性向 Keycloak 请求所有权限的判定,只要其中至少一个被授予就转发请求,因此列出了多个权限或一个权限包含多个 Scope 的路由,会放行只持有其中一部分的用户。这样的请求现在返回
HTTP 403;配置了access_denied_redirect_uri时则跳转到该地址。对于本身已列出 Scope 的静态权限,
http_method_as_scope同样适用:以请求方法命名的 Scope 现在也必须被授予。Scope 名称现在发送时不带前后空格,因此像res#view, delete这样的权限,此前向 Keycloak 请求的是被其忽略的delete,现在要求delete被授予。Keycloak Token 端点的响应无法解析时,插件现在返回HTTP 503。升级前,请确认列出多个权限或 Scope 的路由的用户在 Keycloak 中被授予了全部权限和 Scope。
数据面
-
上游收到的是路由匹配时使用的路径
升级说明路由按 Nginx 规范化之后的请求路径进行匹配:完成百分号解码,解析
..、..%2F、%2e%2e等点段,在#处截断,并合并连续的斜杠。但上游此前收到的是原始请求路径,因此像/admin/..%2Fapi/x这样的请求会匹配/api/*的路由,而上游收到的却是/admin/..%2Fapi/x。现在当 Nginx 规范化了路径时,上游会收到由 Nginx 转义后的规范化路径,其中编码的分隔符会以解码后的形式到达:/a/./b%2Fc到达上游时是/a/b/c。Nginx 只做了百分号解码或只合并了连续斜杠的请求不受影响。没有选项可以恢复之前的行为。如果某个上游依赖于按客户端发送的原样收到点段或编码的斜杠,请在升级前检查它。
-
网关镜像改为基于精简基础镜像构建
升级说明api7-ee-3-gateway镜像现在就是此前以api7-ee-3-gateway-distroless发布的精简镜像,基于 Ubuntu 的镜像不再构建。镜像的名称、标签和默认用户保持不变,但只包含网关所需的库和 BusyBox 工具:没有apt、没有bash,也没有 Perl,因此resty命令行工具无法在其中运行。api7-ee-3-gateway-distroless这个名称不再发布,请改用api7-ee-3-gateway。以root运行的api7-ee-3-gateway-root镜像现在也基于同一精简镜像构建。如果你基于
api7-ee-3-gateway构建自定义镜像,或者在网关容器中运行依赖包管理器、bash或 Perl 的脚本或调试命令,请在升级前做相应调整。
升级须知
上游设置了 tls_verify: true、但没有引用客户端证书或 CA 证书对象(client_certificate 或 ca_certificates)时,无论是单独设置,还是与已弃用的内联 tls 块一起设置,下发给网关的配置都不带证书校验,网关会接受任意上游证书。现在控制面会下发该设置,网关会校验上游证书。上游未引用 CA 证书时,网关使用其 apisix.ssl.ssl_trusted_certificate 配置中的 CA 证书(默认为系统 CA 证书包)校验,并在配置了 proxy_ssl_crl 指令时检查其中的吊销列表。设置了 tls_verify: true 的上游,如果其证书不被网关信任,此前请求成功,现在会返回 HTTP 502。这是该配置本应有的行为。
升级前已保存的这类上游,升级后仍然不会校验证书,因为下发给网关的配置只在服务被保存时才会重新生成。要为它们启用校验,请在控制面升级后重新 保存每个受影响的服务。在此之前,请确认网关信任每个上游的证书(通过 ca_certificates 引用签发该证书的 CA,或将其加入 ssl_trusted_certificate),或者在不需要校验的地方把 tls_verify 设为 false。
本版本中的上游证书校验有两项限制:上游在 ca_certificates 中引用了 CA 证书时,不会对其检查 proxy_ssl_crl 指令中的吊销列表;通过 tls_verify 启用的校验不应用 proxy_ssl_verify_depth。
tls 不能再与证书引用一起使用创建或更新服务或上游时,如果上游同时设置了已弃用的内联 tls 块与 client_certificate 或 ca_certificates,现在会被拒绝,返回 HTTP 400 和 upstream tls cannot be used together with client_certificate or ca_certificates: tls is deprecated, configure the certificates with client_certificate and ca_certificates instead。在 3.10.8 上,这样的写入会被接受,但下发给网关时内联 tls 块会被丢弃,因此内联的客户端证书从未提交给上游。tls_verify 只是一个开关,不属于证书引用,仍可与两者任一同时使用。
已经保存的这类上游会照旧下发给网关,但在删掉内联 tls 块或证书引用中的一方之前, 对其服务或上游的下一次更新都会被拒绝。编辑之前,请先把证书改为通过 client_certificate 和 ca_certificates 配置。
控制面不再包含 3.8.0 之前版本的数据库升级步骤。要从这类版本升级,请先升级到 3.10.8 或更早的 3.8、3.9、3.10 版本,再升级到 3.10.9。
3.4 及更早版本的网关实例用于上报指标的接口也已移除。这类网关实例仍然可以连接控制面,但其指标会被以 HTTP 404 拒绝,因此它们的流量不再出现在监控中。请将这些网关实例升级到更新的版本。
3.10.9 控制面首次启动时,会为没有主键的数据库表添加主键,每张表会因此被重写一次。所需时间以及表被锁定的时间随表的大小增长,最大的表通常是 dataplane_api_calls、gateway_instance 和 consumer_identifier。请据此规划升级窗口。如果你曾为规避 PostgreSQL 逻辑复制报错把这些表设为 REPLICA IDENTITY FULL,升级后可以改回 DEFAULT。
请在网关组的所有网关实例都升级到 3.10.9 之后,再启用新的 Request Decompress 插件以及使用 https:// 服务器地址的 Consul 注册中心。更早版本的网关实例没有该插件,会丢弃使用它的配置,并且会跳过使用 https:// 地址的 Consul 注册中心。
网关运行时现在使用 OpenSSL 3.5,它在 TLS 1.3 握手中增加了后量子混合密钥交换组 X25519MLKEM768。网关发往上游的 TLS ClientHello 因此变大,网 关与上游之间的部分老旧网络设备可能无法正确处理。
新功能
插件
- Request Decompress
- 新插件会解压以
Content-Encoding: gzip或deflate发送的请求体,使路由上的插件(例如 OAS Validator)读取解压后的请求体。默认情况下上游收到解压后的请求体,forward_compressed为true时则收到压缩的请求体。max_req_body_size同时限制收到的请求体和解压后的请求体的大小。
- 新插件会解压以
- Prometheus
- 全部四个流指标
apisix_stream_connection_total、apisix_stream_active_connections、apisix_stream_status和apisix_stream_bandwidth现在都带有service和service_id标签,表示所匹配流路由的服务,并与 HTTP 指标遵循相同的prefer_name规则。活动连接数与带宽在会话仍处于打开状态时就会按服务拆分。没有到达带服务的流路由的会话,仍计入其监听地址的无标签合计。监听地址上出现的每个服务都会占用流指标共享内存区域(nginx_config.stream.metrics_zone_size,默认1m,约可容纳 750 个槽位)中的一个槽位。该区域占满后,新服务的活动连接数与带 宽只计入其监听地址的合计。
- 全部四个流指标
控制面
- Consul 注册中心现在可以使用
https://服务器地址,同一注册中心中可以混用http与https地址;不带端口的https地址使用端口443。新增的ssl_verify选项默认为true,控制是否校验 Consul 服务器的证书,同时作用于网关和控制面自身发起的注册中心查询。在 Dashboard 中,Consul 注册中心表单新增了 SSL Verify 开关。 - Nacos 或 Consul 注册中心现在可以通过新增的
allow_control_plane_access选项标记为控制面不可访问,默认值为true。设为false时,控制面不会向该注册中心发出任何请求,用于填充命名空间、分组、数据中心和服务选择框的注册中心查询会直接被拒绝,返回HTTP 400和control plane access to this service registry is disabled (allow_control_plane_access is false),而不是以连接错误失败。网关仍会像以前一样从该注册中心发现服务节点。在 Dashboard 中,注册中心表单新增了 Allow Control Plane Access 开关;使用已关闭该开关的注册中心的服务,以手动输入文本的方式填写要发现的服务(Nacos 还包括命名空间、分组和元数据),而不是从选择框中选择。 - 注册中心的状态现在反映网关组内所有在线网关实例的情况,而不再取决于最后一个上报的实例。所有在线实例都能连接时为
healthy,都无法连接时为lost_connection,只有部分实例能连接时 为新增的partially_lost_connection;注册中心的 API 响应会在lost_connection_instances中列出已失去连接的实例,包括主机名和各自失去连接的时间。离线实例不参与统计。新增告警事件 Service Registry Lost Connection(service_registry_lost_connection):网关组内任一在线网关实例与某个注册中心失去连接超过所配置的时长时通知一次,恢复后再次失去连接时才会再次通知。在 Dashboard 中,部分失去连接的注册中心以单独的标签显示,鼠标悬停在状态上会列出失去连接的实例。 - 当用于监控的 Prometheus 中还保存着其他系统(例如开源 APISIX)的同名指标时,现在可以配置额外的标签匹配器,例如
job != "apisix",它们会被加到监控页面、共享字典监控以及基于 Prometheus 的告警策略的每个指标查询中。可以在 Dashboard 的 Gateway Settings > Monitoring 中管理,也可以通过/api/system_settings/monitoring管理。
控制台(Dashboard)
- 在编辑表单中,内容发生修改之前 Save 按钮处于禁用状态。
- OpenID Connect 插件的快速开始模板现在可以折叠,为配置编辑器留出更多空间。添加插件时模板默认展开;编辑已有配置或应用模板后,模板会折叠。
缺陷修复
插件
- Limit Count、Limit Count Advanced 和 GraphQL Limit Count
- 修复问题:
rules列表中两条规则的key相同时,控制面会接受,但网关会拒绝该配置。路由、服务、全局规则、消费者或 Workflow 动作被保存了,但网关会丢弃它:新建的路由返回HTTP 404,更新的路由则继续运行之前的配置。现在这样的配置会被拒绝,返回HTTP 400和invalid limit-count plugin: duplicate key '<key>' in rules。
- 修复问题:
- AI Proxy 和 AI Proxy Multi
- 修复问题:对于 Anthropic Messages 协议,prompt token 数没有包含缓存读取和缓存写入 token;在流式响应中,只在最后的
message_delta事件里上报的缓存 token 完全没有被读取。因此对于使用了 prompt 缓存的请求,$llm_prompt_tokens、$llm_total_tokens、apisix_llm_prompt_tokens,以及 AI Rate Limiting 在total_tokens或prompt_tokens策略下消耗的配额都偏低。现在 prompt token 包含缓存读取和缓存写入 token,与 OpenAI 兼容服务商一致。Anthropic 客户端经由 OpenAI 兼容上游提供服务时,转换后响应中的input_tokens不再包含缓存写入 token,因此不会再被重复计算。 - 修复问题:对于 Amazon Bedrock,prompt token 数没有包含 Converse API 单独上报的缓存读取和缓存写入 token,缓存 token 计数也始终为零,流式和非流式响应都是如此。因此对于使用了 prompt 缓存的请求,日志和指标中的 token 用量,以及 AI Rate Limiting 消耗的配额都偏低。现在 prompt token 包含缓存读取和缓存写入 token。
- 修复问题:对于 Anthropic Messages 协议,prompt token 数没有包含缓存读取和缓存写入 token;在流式响应中,只在最后的
- OAS Validator
- 修复问题:从
spec_url获取的规范在没有任何路由再使用后,仍然留在每个 worker 的内存中;修改插件元数据中的spec_url_ttl后,之前缓存中的所有规范也都不会释放。对于spec_url经常变化的路由(例如带版本号的规范地址),worker 内存会随每次变化而增长,直到 worker 内存耗尽。现在在spec_url_ttl秒内没有被任何请求使用的规范会被释放。
- 修复问题:从
数据面
- 修复问题:Consul 的 catalog 与 health 两个监听几乎同时返回时,Consul 服务发现可能停滞。网关记录
bad argument #1 to 'str_sub' (string expected, got boolean),不再从注册中心获取变更,使用该注册中心的路由可能返回HTTP 503和consul service not found。每次发生还会在网关的特权进程中泄漏一个连接,泄漏到一定数量后,其所有后台任务都无法运行,包括向控制面发送心跳。 - 修复问题:网关实例启动时或注册中心配置变更时就已经无法连接的注册中心,从来不会被上报为失去连接,其状态会一直停留在
connecting,直到恢复连接。健康检查只失败了一次探测的注册中心,也可能被上报为失去连接。现在每个网关实例只在健康检查达到不健康阈值后才把注册中心上报为失去连接,并且只在一次探测成功之后才上报为健康。
控制面
- 修复问题:Nacos 或 Consul 注册中心的服务器地址不带端口(例如
http://registry.example)且配置了健康检查时,下发给网关的健康检查端口为空。网关随后会中止服务发现的初始化,因此使用该网关组其他注册中心的路由(包括带端口的注册中心)也可能返回HTTP 503。现在控制面对http使用端口80、对https使用端口443,即网关的注册中心客户端实际连接的端口。已有的注册中心无需编辑即可获得该端口。 - 修复问题:从 Dashboard 发起的 Nacos 或 Consul 查询失败时,错误信息(也会显示在 Dashboard 中)可能包含注册中心的凭据:Nacos 访问令牌、AK/SK 签名参数,以及
user:password@形式服务器地址中的用户名。现在错误信息只包含主机、路径和失败原因。 - 修复问题:并发写入多个全局规则时(例如 ADC 并行同步全局规则插件时),部分插件可能从下发给网关的配置中丢失,而控制面中仍然列出它们,之后再执行
adc sync也发现不了差异,无法修复。在 SQL Server 上,这类并发写入还可能因死锁返回HTTP 500或HTTP 504。现在写入的每个插件都会被下发,并发写入也不再死锁。 - 修复问题:审计日志表很大时,每晚的过期审计日志清理会超时并回滚,一条也没有删掉,过期日志因此不断累积。现在过期日志按事件时间分批删除,积压的数据会在升级后的第一次清理中删除。
- 修复问题:DP Manager 的访问日志会记录网关每次按 key-auth 查询消费者以及查询开发者门户凭据时使用的明文 API key,查询不存在的 key 时,
HTTP 404响应体中也会包含该 key。现在访问日志中的 key 会被屏蔽为***,响应中也不再包含它。 - 修复问题:配置规模很大(例如数万个服务和路由)时,Dashboard 启动失败并报
Failed to start: context deadline exceeded,之后每次重启都会失败。现在 Dashboard 启动时加载配置更快,并且不再设置固定的启动期限,启动可以耗时多久交由部署平台(例如 Kubernetes 探针)约束。 - 修复问题:部署多个 Dashboard 副本时,通过一个副本写入的服务或路由,最长要过五分钟才会被其他副本的路由冲突检查纳入,在此期间可能创建出相互冲突的路由。
- 修复问题:证书、CA 证书和 SNI 的使用情况列表,以及服务列表的
hosts过滤,匹配服务的方式与网关匹配 SNI 的方式不一致,结果还因数据库而异。视数据库不同,通配 SNI 中的点号可能匹配任意字符,通配 SNI 可能一个服务都匹配不到或匹配多级子域,host 中的_可能匹配任意单个字符。现在所有数据库上通配值只匹配一级 label,其他值只匹配完全相同的 host。 - 修复问题:在开启了逻辑复制的 PostgreSQL 上(托管数据库的蓝绿部署就使用逻辑复制),由于多张控制面数据表没有主键,对它们的更新和删除会失败,导致网关心跳和网关实例删除返回
HTTP 500。现在每张控制面数据表都有主键。参见上文的升级说明。
控制台(Dashboard)
- 修复问题:在告警策略中,为状态码类事件选择了服务或路由后再切换到其他事件,隐藏的服务或路由仍会保留在策略的作用范围中。
- 修复问题:资源详情页的标题会截断较长的标签值。现在会显示完整的值。
- 修复问题:打开 Jaeger 中已不存在的调试会话链路时,只显示通用的错误信息。现在 Dashboard 会说明该链路在 Jaeger 中已不可用。
3.10.8
发布日期:2026-10-09
不兼容变更
插件
-
升级说明
通过远程 introspection 校验 Token 时,
claim_validator.issuer.valid_issuers中的签发者白名单现在会真正生效。introspection 响应中的iss缺失或不在白名单内时,请求会被拒绝,返回HTTP 401和WWW-Authenticate: Bearer realm="apisix", error="invalid_token", error_description="issuer validation failed",请求不会到达上游。在 3.10.7 上,introspection 路径不会应用这份白名单,这样的 Token 会被转发到上游。升级前,请检查所有同时配置了
introspection_endpoint和claim_validator.issuer.valid_issuers的openid-connect路由,确认身份提供方的 introspection 响应中带有位于白名单内的iss。 -
升级说明
数据面现在会按照 SAML 规范的要求校验 SAML 响应,且无需任何新增配置。出现以下任一情况时,登录会被拒绝:断言带有
AudienceRestriction,但其中没有列出本服务提供方(未设置sp_audiences时即sp_issuer);断言的使用时间超出其NotBefore与NotOnOrAfter窗口 60 秒以上;断言的Recipient,或响应的Destination,与本服务提供方的断言消费服务(ACS)URL 不一致;断言对应的登录请求并非当前会话发起的那一个。此外,身份信息现在只会从已验证签名覆盖的断言中读取。在 3.10.7 上,以上各项都不会被检查。未设置
sp_acs_url时,ACS URL 由回调请求的协议和主机拼出。如果网关部署在终止 TLS 却不设置X-Forwarded-Proto、或会改写主机名的负载均衡器或 Ingress 之后,网关拼出的 URL 就会与身份提供方写入Recipient的 URL 不一致,升级后所有登录都会被拒绝。升级数据面前,请为部署在此类代理之后的路由把
sp_acs_url设置为对外的回调 URL;如果身份提供方签发断言时使用的受众不是sp_issuer,请设置sp_audiences;并确保网关的时钟已同步。网关实例升级时正在进行中的登录会重新开始,而不会被拒绝。 -
batch-requests
升级说明在 3.10.1 引入的子请求数量上限之外,该插件现在还会限制其聚合的响应体大小。单个子响应超过
max_response_body_size(默认1048576字节,即 1 MiB),或一个批次的子响应合计超过max_response_body_size_total(默认10485760字节,即 10 MiB)时,会返回HTTP 502,例如{"error_msg":"response body of pipeline request 1 exceeds max_response_body_size"}。没有Content-Length的子响应同样会被计量。在 3.10.7 上,这两项限制都不存在,每个子响应体都会被完整缓存。两项限制都是
batch-requests插件元数据的配置项。如果业务依赖批量获取大响应,请在升级数据面前调大这两个值。 -
升级说明
每条规则的
actions现在必须恰好包含一个[name, conf]。带有多余元素的动作和包含多个动作的规则,在 3.10.7 上会被接受、存储并正常运行。控制面现在会拒绝这两种形状,返回HTTP 400和指明问题的消息,例如invalid workflow plugin: invalid action: expected [name, conf]或workflow plugin: rules.0.actions: Array must have at most 1 items。升级前已存储的这两种形状的 workflow 配置,在其网关实例升级后会成为配置兼容性报告中的 error 级别条目,需要先改正才能再次编辑。
升级须知
Stream 路由现在可以通过控制面配置 sni、snis 和 tls_passthrough。Stream 路由带有数据面不支持的字段时,数据面会拒绝整条 Stream 路由,该路由在对应网关实例上随即停止服务。snis 从 3.10.8 起才被支持,因此 3.10.7 及更早版本的数据面会拒绝设置了它的 Stream 路由;tls_passthrough 从 3.10.7 起被支持。
API7 企业版按先控制面、后数据面的顺序升级。在网关组的所有数据面都运行 3.10.8 之前,不要在 Stream 路由上配置 snis;只要还有数据面低于 3.10.7,就不要使用 tls_passthrough。单个 sni 在本控制面接受的所有数据面版本上都受支持。
新功能
插件
- SAML Auth
- 新增若干配置项,用于收紧或调整登录响应的校验方式。
idp_issuers限定接受哪些签发者;sp_audiences设置本服务提供方所对应的受众;sp_acs_url固定断言消费服务 URL,而不是由请求拼出;clock_skew设置断言时间戳的容差(默认60秒)。replay_dict指定一个共享字典,已接受的断言会在其中保存到它不再可被接受为止再加上clock_skew,不带过期时间的断言则保存replay_ttl秒(默认600),使每条断言在同一个网关实例上只能被接受一次。字典已满时,登录仍会成功,但该断言不会被记录,网关会记录一条错误日志。网关默认为此声明了plugin-saml-auth-replay(10 MiB),其大小可在网关配置文件的nginx_config.http.lua_shared_dict下修改。
- 新增若干配置项,用于收紧或调整登录响应的校验方式。
- OpenAPI to MCP
- 新增
cache_enabled(默认true)和cache_ttl(默认3600秒),使每条路由可以自行决定其 OpenAPI 文档生成的工具缓存多久。把cache_enabled设为false后,每个会话都会重新读取文档,适合文档仍在变动的情况。这两个配置项需要api7/openapi-to-mcp边车 1.0.5 或更高版本;本版本随附 1.0.6。
- 新增
- Limit Count、Limit Count Advanced、GraphQL Limit Count、Limit Conn、Limit Req、AI Rate Limiting 和 AI Cache
- 与 Redis 建立 TLS 连接时现在会发送服务器名称(SNI),新增的
redis_server_name配置项用于设置它。未设置时发送redis_host,但redis_host为 IP 地址时不发送。此前不会发送任何服务器名称,因此开启redis_ssl后,无法连接按名称路由 TLS 连接的 Redis 端点,许多托管 Redis 服务都属于这种情况。
- 与 Redis 建立 TLS 连接时现在会发送服务器名称(SNI),新增的
- AI Rate Limiting
cost_expr现在可以使用嵌套在对象中的数值型 usage 字段,字段名由各层键名以__连接而成。例如,OpenAI Responses API 把缓存 Token 数放在input_tokens_details下的cached_tokens中,表达式中写作input_tokens_details__cached_tokens。顶层字段的名称不变,现有表达式不受影响。连接后的字段名需要 3.10.8 的数据面;较早版本的数据面会把它们计为0,导致请求的计费低于表达式的本意。
- Limit Count、Limit Count Advanced、GraphQL Limit Count 和 AI Rate Limiting
$rate_limiting_info变量现在还会描述请求所计入的窗口:窗口类型和大小、请求是被放行还是被拒绝、请求给计数器增加了多少、当前窗口的起止时间和计数、滑动窗口中加权后的上一个窗口,以及延迟同步判定时所依据的快照。计数器无法更新的请求(例如 Redis 不可达时)会被记录为decision为error,而不会看起来像被拒绝;键中含有引号或反斜杠时,该变量的值也不再是非法 JSON。字段顺序不再固定,并且新增了字段,因此按位置解析该值的日志处理流程必须改为按 JSON 解析。
控制面
- Stream 路由现在可以按客户端 TLS 握手中的服务器名称(SNI)匹配,并可以把 TLS 会话透传给后端。
sni设置一个名称,snis设置多个;*.example.com这样的名称匹配example.com下的所有名称,单独的*匹配任意名称,匹配不区分大小写,两个字段不能同时设置。在网关配置文件中同时声明了tls和tls_passthrough的监听端口上,由匹配到的 Stream 路由上的tls_passthrough决定连接是原样透传,还是在网关上终止 TLS。这些字段可以通过 Admin API 和 Dashboard 的 Stream 路由表单配置。此前控制面会丢弃它们,因此同一端口上的 Stream 路由无法按 SNI 区分。各字段所需的数据面版本参见升级须知。 - 现在可以通过路由 ID 查找服务。服务列表接口的
search参数还会完整或部分匹配网关组中 HTTP 路由和 Stream 路由的 ID,并返回该路由所属的服务。以空白分隔的多个关键词仍按 AND 语义组合,因此一次查询可以同时包含服务字段和路由 ID。Dashboard 的服务搜索提示也已加入这一匹配方式。 - 离线安装包现在包含
api7/openapi-to-mcp边车镜像,因此在离线环境中也可以使用openapi-to-mcp和mcp-tools-acl插件。run.sh start会加载该镜像;边车仍需在网关旁、与网关处于同一网络命名空间中启动。