更新日志
3.10.7
发布日期:2026-09-08
不兼容变更
插件
-
升级说明
Basic Auth 的密码不能再为空。控制面现在会拒绝密码为空字符串的消费者或凭据,返回
HTTP 400和basic-auth plugin: password: String length must be greater than or equal to 1。在 3.10.6 上,同样的请求会返回HTTP 200并被存储下来。升级后,已存储的空密码消费者会在配置兼容性报告中变成一条 error 级别的条目,并且对它的任何后续修改都会被拒绝,直到设置了密码为止。
数据面现在同样按失败关闭处理:解析结果为空字符串的密码(包括解析结果为
""的$env://或$secret://引用)会被拒绝,返回HTTP 401并在错误日志中记录一条 warning。在 3.10.6 上,这样的消费者用「用户名 + 冒号 + 一个空格」这样的凭据即可认证成功。升级前请检查是否存在密码为空、或密钥引用解析结果为空的 Basic Auth 消费者和凭据,并为它们分别设置真实的密码。
控制面
-
网关无法区分的路由会被拒绝
升级说明创建或更新路由(
POST/PUT/PATCH /apisix/admin/routes)以及更新服务(PUT/PATCH /apisix/admin/services/{id})时,如果结果会让同一个网关组中出现两条在相同优先级下、对相同 HTTP 方法匹配相同 URL 的路由,请求现在会被拒绝,返回HTTP 400。从 OpenAPI 规范导入服务同样会因此被拒绝,因为它经由同一条路径创建路由——因此其操作会归并成两条无法区分的路由的规范,现在无法再导入。错误信息中会指出与之冲突的那条路由,例如route "get-again" conflicts with route "get" (id: ...) of service "first" (id: ...): both match "httpbin.org/get" for all HTTP methods at priority 0.只有相同优先级下的完全重复才会被拒绝。匹配相同 URL 但优先级不同、HTTP 方法只是部分重叠或完全不相交、路径是包含关系而非完全相同的两条路由,仍然会被接受;带
vars的路由同样不受影响,因为它们基于 URL 比较无法表达的条件进行匹配。未激活的服务被排除在外,而重新激活时会进行检查,因此无法借由未激活的服务把重复路由夹带进来。此前只有 Dashboard 的路由冲突弹窗划出了这条界线,因此 ADC、
a7以及直接调用 Admin API 的调用方都可以写入网关无法区分的路由,而且没有任何地方会提示。升级后已有的重复路由仍然继续处理流量,但对其中任意一条路由的下一次修改都会被拒绝;对拥有这样一对路由的服务而言,任何更新都会被拒绝——包括仅修改描述或标签——因为每一次更新服务都会重新校验它下面的所有路由。升级 前请检查网关组中是否存在重复路由,并为每一对中的一条改用不同的路径、不同的 HTTP 方法或不同的优先级。
升级须知
兼容性报告现在按问题分组,忽略规则则按数据面上报的机器可读 reason 进行匹配。两者都依赖数据面以结构化数据的形式上报兼容性问题,这一能力在 3.10 线自 3.10.7 起具备,在 3.9 线自 3.9.20 起具备。API7 企业版的升级顺序是先控制面、后数据面,因此在升级窗口内,3.10.7 的控制面面对的是尚未以这种方式上报的网关实例,对这些实例来说两个能力都不生效。
这类数据面把每个问题上报为一句渲染好的英文句子,其中不含机器可读的 reason。控制面在心跳到达时就会丢弃这类记录,因此该实例的兼容性报告是空的。实例上真实存在的问题——被数据面拒绝的资源、数据面没有的插件——都不会展示出来,忽略规则也没有任何可作用的对象。受影响的是 3.10 线上低于 3.10.7、3.9 线上低于 3.9.20,以及所有 3.9 线之前的网关实例 ——支持范围从 3.2 起算,这些版本同样不会上报结构化问题。运行 3.9.20 或更高版本的实例上报的是结构化问题,本控制面可以正常渲染。请预期在这类实例完成升级之前报告是空白而非可信的,不要把空白的报告当作没有问题。
实例本身仍会由版本规则标记为需要升级,因此不会悄无声息地显示为已是最新。这只影响兼容性报告的展示。它不会影响流量,也不会影响网关实例实际运行的配置;网关实例升级完成后,报告即恢复为文档描述的行为。
ca_certs 列表现在会被拒绝控制面现在会拒绝上游中把 tls.ca_certs 设为空列表的 traffic-split 插件配置,返回 HTTP 400。在 3.10.6 上,同样的写入会被接受。
这只涉及插件配置这条路径。以常规方式配置的上游不受影响:控制面在下发之前就会丢弃空的 ca_certs,这种形态从来不会被下发到数据面。
这类配置在 3.10.6 上其实也从未生效:数据面的上游 schema 校验会失败并丢弃该配置,而控制面却报告成功。真正的变化是,原本静默的失败现在会被明确地报出来。
如果已经存有 tls.ca_certs 为空的 traffic-split,请为它配置 CA 证书或删除其中的 tls 块。在此之前,对该 traffic-split 的任何修改都会被拒绝。
Console 重新由 dashboard 进程提供服务,形式是一个用 Vite 构建的静态单页应用。对于不是直接使用发行包中原始文件的部署,这会带来三点影响。
一体化镜像中不再包含 Node.js,也不再包含 shell:它的基础镜像换成了 static distroless 镜像,entrypoint 变成 dashboard 二进制本身。离线包中的 docker-compose.yaml 直接启动该二进制,并用 api7-ee-dashboard healthz 做健康检查。如果你把 3.10.6 中自定义的 command 或 healthcheck(即在 dashboard 之外再启动 node /app/server.js 的那一份)原样沿用过来,容器将无法启动。请以新离线包中的 compose 文件为基础,再把你自己的改动叠加上去。由于镜像中没有 shell,docker exec ... sh 进入 dashboard 容器以及基于 shell 的 entrypoint 覆盖都不再可用。
浏览器静态资源从 Next.js 的 /_next/static/ 路径迁移到了 /assets/ 下带内容哈希的文件。任何固定匹配 /_next/static 的反向代理规则、Content-Security-Policy 或 CDN 缓存键都将不再命中,需要改指向 /assets/。
开发者门户前端镜像(api7-ee-developer-portal-fe)现在同样是 distroless 镜像,也不含 shell,因此上述限制同样适用;它原本就以非 root 用户运行,启动行为(包括数据库与门户连通性检查)也保持不变。
新功能
插件
- JWE Decrypt
- 新增的认证插件,用于解密客户端提交的 JSON Web Encryption 令牌,根据令牌的 key ID 确定消费者,并把解密出的内容通过可配置的请求头转发给上游。消费者的密钥为 32 字节,可以直接以明文提供,也可以使用 base64url 编码;令牌必须使用
dir密钥管理算法和A256GCM内容加密算法。令牌缺失、格式非法、被篡改或无法解密的请求都会被拒绝,其中令牌缺失时的处理方式可以配置。该插件只负责解密令牌,不提供任何签发令牌的接口。它可以像其他认证插件一样在 Dashboard 中配置。
- 新增的认证插件,用于解密客户端提交的 JSON Web Encryption 令牌,根据令牌的 key ID 确定消费者,并把解密出的内容通过可配置的请求头转发给上游。消费者的密钥为 32 字节,可以直接以明文提供,也可以使用 base64url 编码;令牌必须使用
- Chaitin WAF
- 现在可以在上报请求的同时把响应一并上报给长亭雷池(SafeLine)检测服务,这样响应体中泄露的数据、漏洞利用的输出,或者异常的状态码都能被雷池看到。插件和插件元数据上都提供了三个配置项:
config.log_resp开启响应上报,config.resp_body_size以 KB 为单位限制上报的响应体大小(0表示只上报响应头),config.extra_ignored_content_types在内置忽略列表之外,以逗号分隔追加需要跳过的响应 content type。响应上报默认关闭。上报发生在响应已经返回给客户端之后,且仅供参考:它不会阻断也不会修改响应。
- 现在可以在上报请求的同时把响应一并上报给长亭雷池(SafeLine)检测服务,这样响应体中泄露的数据、漏洞利用的输出,或者异常的状态码都能被雷池看到。插件和插件元数据上都提供了三个配置项:
- AI Proxy Multi
- 实例的健康检查状态现在可以通过数据面 control API 查看。
GET /v1/healthcheck会为每个声明了checks的实例列出一个条目,条目中带有新增的plugin和meta字段(meta.instance给出实例名),同时新增了子资源GET /v1/healthcheck/{src_type}/{src_id}/checkers,以数组形式返回某个资源拥有的全部健康检查器。此前,真实上游是 LLM 实例的路由什么都不会上报,GET /v1/healthcheck/{src_type}/{src_id}也只会返回HTTP 404和no checker for routes[1]。
- 实例的健康检查状态现在可以通过数据面 control API 查看。
控制面
- 现在可以在网关旁边部署诊断 Agent,并从 Dashboard 对运行中的数据面做诊断——采集网关自身 worker 进程的 CPU profile 和内存快照——而无需在网关所在网络上开放任何入站端口。Agent 通过 mTLS 主动向控制面拨号,使用的正是数据面已经在用的端口,Dashboard 再经由这条连接把请求转发过去。API Runtime 下新增了集群级的 Diagnostic Agents 板块:列出各个 Agent 及其状态,为每个在线的 Agent 打开诊断控制台,并为新 Agent 生成可直接运行的 Docker 命令或 Kubernetes 清单,其中已经填好证书、与宿主机共享的 PID 命名空间以及诊断运行所需的各项 capability。每个 Agent 在 部署时命名,该名称写入它被签发的证书中,因此列表里展示的是机器标识而不是一串裸 ID。
- 网关实例的配置兼容性报告现在按问题组织,而不是按资源组织。
GET /api/gateway_groups/{gateway_group_id}/instances/{gateway_instance_id}/compatibility_issues为每一个不同的问题返回一个条目——包含机器可读的reason(resource_invalid、plugin_unavailable、plugin_config_invalid、plugin_unknown_fields)、它所涉及的插件和字段,以及携带该问题的资源列表——并按错误优先、其次按受影响资源数量排序。数据面现在以结构化数据上报每个问题,而不是为每个资源渲染一句英文,因此同一个原因不会再在成千上万行里重复出现,未识别字段的告警也不会再被聚合后的错误淹没。Dashboard 的网关实例页面即以这种分组形式展示该报告。 - 运维人员现在可以忽略某个数据面不识别但会安全跳过的插件字段,让兼容性报告只列出真正需要处理的内容。一条忽略配置指定插件和字段,对所有网关组和实例生效,并覆盖数组中的每一个元素——忽略
nodes[*].weight即覆盖全部元素。忽略配置既可以在 Dashboard 的网关实例页面上维护,也可以通过/api/compatibility_dismiss_rules接口管理,它们有自己的权限控制,每一次变更都会记入审计日志。只有未识别字段的告警可以被忽略:忽略其中一条告警既不会改变数据面对配置的处理方式,也不会把 Incompatible 的实例变成 Compatible。 - 现在可以按域名或路径前缀查找服务。服务列表接口的
search参数除了名称、描述、标签和 ID 之外,还会不区分大小写地匹配服务hosts或path_prefix的任意子串;以空白字符分 隔的多个词仍然是 AND 语义。此前,只知道服务域名或路径前缀的用户没有任何办法把它找出来。升级前发布的服务无需重新发布即可按这种方式搜索。
数据面
- stream 代理现在可以把 TLS 会话透传给后端,而不是在网关上终结。在网关配置文件的
apisix.stream_proxy下声明了tls_passthrough: true的 TCP 监听端口,会读取客户端 ClientHello 中的 SNI,据此选择后端,并把加密的会话原样转发过去,TLS 会话因此在后端终结。到达该端口的每一条连接都会被透传;该端口在网关自身的配置中声明——Docker Compose 部署中位于gateway_conf/config.yaml,Kubernetes 上则位于网关 Helm chart 的 values 中。 - 以
101 Switching Protocols应答的请求现在被归类为request_type=websocket,因此 WebSocket 会话会落到各自独立的apisix_http_status、apisix_http_latency和apisix_bandwidth时间序列中,可以用request_type!="websocket"把它们排除在延迟查询之外。普通请求的时间序列保持不变,握手被拒绝的请求仍然是traditional_http。如果你的仪表盘或告警规则在聚合这些指标时没有按request_type过滤,将会看到 WebSocket 流量从原先所在的序列中被分离出去。