更新日志
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会加载该镜像;边车仍需在网关旁、与网关处于同一网络命名空间中启动。
控制台(Dashboard)
- 服务、路由、Stream 路由、消费者和全局规则上的插件卡片新增了启用/禁用开关,插件编辑器中也有同样的开关。禁用插件会保留其配置,并让网关不再执行它。此前需要手动编辑
_meta.disable才能做到。 - 控制面版本号显示在侧边菜单底部的页脚中,点击即可复制。
缺陷修复
插件
- AI Aliyun Content Moderation
- 修复问题:流式返回的模型响应不带
usage字段时,最终的审核检查会被跳过,客户端收到的回答不带任何审核结果。如果响应结束时也没有[DONE]事件,客户端就一直收不到它。现在最终检查总会执行并报告结果,上游未发送[DONE]时由网关补发。被网关的max_response_bytes或max_stream_duration_ms截断的流仍然不会以[DONE]结束。
- 修复问题:流式返回的模型响应不带
- AI Proxy
- 修复问题:周期性刷新时如果没有新内容可发送,流式响应可能被提前截断,并被记录为客户端断开。SSE 事件被拆分到多次读取中,或者有插件缓存响应体时,都可能出现这种情况。
- feishu-auth 和 dingtalk-auth
- 修复问题:授权码没有绑定到发起登录的浏览器会话,因此从别处获得的授权码在任何出示它的会话上都会被接受(登录 CSRF)。现在跳转到身份提供方时会携带一个随机的
state,回调中state缺失或与会话不匹配时,请求会被拒绝,返回HTTP 401和{"message":"Invalid state"}。网关实例升级时正在进行中的登录需要重新开始。自行获取授权码的集成应通过X-Feishu-Code或X-DingTalk-Code请求头传入授权码,该方式的处理与之前相同。
- 修复问题:授权码没有绑定到发起登录的浏览器会话,因此从别处获得的授权码在任何出示它的会话上都会被接受(登录 CSRF)。现在跳转到身份提供方时会携带一个随机的
- Prometheus
- 修复问题:指标库
nginx-lua-prometheus-api7在 3.10.5 中进行了升级。在 3.10.5、3.10.6 和 3.10.7 上,如果在网关配置文件的plugin_attr.prometheus.metrics下为 指标设置了expire,该指标库可能导致网关 worker 出现 CPU 突刺。为避免这一问题,本版本将指标库回滚到 3.10.1 及更早版本所用的版本。expire选项仍然生效,无需修改任何配置。
- 修复问题:指标库
- Limit Count、Limit Count Advanced 和 GraphQL Limit Count
- 修复问题:设置了
sync_interval时,只拒绝请求的网关实例在其本地计数过期后,就不再从 Redis 刷新缓存的配额,而是依据过时的数值持续拒绝请求,直到缓存的配额本身过期。使用滑动窗口时,这样的实例会在窗口剩余时间内一直沿用上一个窗口的权重,放行的请求远少于限额允许的数量。Redis 不可达时,这样的实例还会在每次同步时给本地的回退计数器计数,尽管它没有放行任何请求。
- 修复问题:设置了
数据面
- 修复问题:开启
apisix.normalize_uri_like_servlet后,发往上游的请求与参与路由匹配的请求不一致。路径中百分号编码的?(%3F)会被解码,导致其后的内容全部变成查询字符串;客户端自己的查询字符串会被丢弃;服务的strip_path_prefix会被忽略,上游收到的路径仍带着前缀。 - 修复问题:引用了数据面上不存在的插件(例如未对该网关组启用的自定义插件)的 Stream 路由会被整条丢弃,导致该路由停止服务。现在会跳过该插件,路由继续工作,与 HTTP 路由原 有的行为一致。被跳过的插件不会执行,因此如果它承担访问控制(例如
ip-restriction),请确认该插件已对网关组启用。 - 修复问题:配置兼容性报告不包含 Stream 路由,因此即使某些 Stream 路由的配置无效或引用了不可用的插件,网关实例仍可能被报告为没有问题。现在 Stream 路由会像其他资源一样被报告。
- 修复问题:网关启动过程中写入的配置变更可能丢失且没有任何报错,因为配置监听可能在 etcd 可达之前就已启动。受影响的 worker 会一直运行旧配置,直到同一资源再次被修改。
- 修复问题:网关的 RPM 安装包不包含 S3 和 Azure Blob 客户端库,因此通过 RPM 安装的网关无法使用以 S3 或 Azure Blob 存储为后端的回退控制面。
控制面
- 修复问题:Workflow 规则中的动作没有配置时(例如
[["return"]]),控制面会返回HTTP 500,路由也不会被创建。现在这样的规则会被拒绝,返回HTTP 400和invalid workflow plugin: invalid action: expected [name, conf]。 - 修复问题:控制面会接受网关无法运行的 DeGraphQL
query,包括 subscription、null字面量、块字符串,以及片段定义或变量定义上的指令。路由可以保存,但网关会丢弃它,访问该路由返回HTTP 404。现在这样的查询会被拒绝,返回HTTP 400和指明具体语法的消息,例如degraphql does not support subscription operations。反过来,选择集为空的查询网关可以运行,现在也会 被接受。 - 修复问题:JWE Decrypt 消费者的密钥以
$env://或$secret://引用给出时会被拒绝,返回HTTP 400和the secret length should be 32 chars(设置了is_base64_encoded时为the secret should be a base64url encoded string),因为控制面把引用本身当作密钥来校验。现在引用会按原样保存,由网关在运行时解析。 - 修复问题:将 3.8.x 或 3.9.x 的控制面直接升级到 3.10.6 或 3.10.7 时,如果有服务使用了自定义插件,升级会失败:dashboard 不断重启并报
custom plugin encrypt fields not found in cache,始终无法启动;先升级到 3.10.5 再继续升级则不受影响。直接升级到 3.10.8 可以完成,结果数据与分两步升级相同。 - 修复问题:调试会话中列出的链路已不在 Jaeger 中时(超出保留期,或者在内存中保存链路的 Jaeger 重启后丢失),打开或下载该链路会返回空的
HTTP 500;Jaeger 无法访问时,任何此类请求也会返回同样的错误。现在链路详情和下载接口会返回HTTP 410并说明该链路在 Jaeger 中已不可用,或返回HTTP 503和Jaeger is unavailable。
控制台(Dashboard)
- 修复问题:在调试会话的链路视图中,每个跨度名称前都带着同一个服务名前缀,且跨度名称列无法调宽。现在去掉了该前缀,列宽可以调整,服务名仍会显示在跨度详情中。
- 修复问题:点击顶部菜单中的菜单项时,如果正要离开的页面在下一个页面 仍在加载时更新了自己的地址,点击可能没有任何反应,或者跳回首页。
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 Token,根据 Token 的 key ID 确定消费者,并把解密出的内容通过可配置的请求头转发给上游。消 费者的密钥为 32 字节,可以直接以明文提供,也可以使用 base64url 编码;Token 必须使用
dir密钥管理算法和A256GCM内容加密算法。Token 缺失、格式非法、被篡改或无法解密的请求都会被拒绝,其中 Token 缺失时的处理方式可以配置。该插件只负责解密 Token,不提供任何签发 Token 的接口。它可以像其他认证插件一样在 Dashboard 中配置。
- 新增的认证插件,用于解密客户端提交的 JSON Web Encryption Token,根据 Token 的 key ID 确定消费者,并把解密出的内容通过可配置的请求头转发给上游。消 费者的密钥为 32 字节,可以直接以明文提供,也可以使用 base64url 编码;Token 必须使用
- 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 流量从原先所在的序列中被分离出去。
缺陷修复
插件
- Basic Auth
- 修复问题:密码中包含冒号的消费者永远无法通过认证。RFC 7617 规定第一个冒号之后的全部内容都是密码,但此前的实现按每一个冒号切分凭据,把密码截断了。
- 修复问题:密码为空的消费者——无论是直接存成空字符串,还是由
$env://或$secret://引用解析出空值——会让任何携带其用户名和空密码的请求通过认证。现在这样的消费者会被拒绝,返回HTTP 401,并且空密码也无法再被配置。升级前需要检查的内容请参见不兼容变更。
- UA Restriction
- 修复问题:携带多个
User-Agent头的请求,在这些 User-Agent 命中denylist时反而被放行,未命中时反而被拒绝——只要请求带有一个以上的该请求头,判定就是反的。因此被拒绝的客户端只要把同一个User-Agent发送两次就能绕过限制。现在这类请求会被正确拒绝,返回HTTP 403。只带一个User-Agent头的请求,以及allowlist分支,从来不受此问题影响。
- 修复问题:携带多个
- Chaitin WAF
- 修复问题:在路由或服务级别的
config中设置任意一个配置项,都会重置该config未设置的其余所有配置项,丢弃插件元数据中配置的值。只设置了read_timeout的路由会静默地把req_body_size、connect_timeout等等都退回到内置默认值。现在插件级别的config会逐字段覆盖元数据,与文档中此前的描述一致。
- 修复问题:在路由或服务级别的
- AI Cache
- 修复问题:在
passthrough协议下,请求体相同但方法、路径或查询字符串不同的请求会共用同一条缓存,因此通配路由上发往/v1/images/generations的请求可能被返回此前发往/v1/chat/completions的请求的缓存响应。该协议的缓存键现在包含客户端的方法、路径和查询字符串。其他协议的缓存键保持不变,因此升级前已缓存的条目仍然有效。
- 修复问题:在
- AI Proxy 和 AI Proxy Multi
- 修复问题:使用 Vertex AI 提供方时,
model中包含/、?或空格的向量嵌入请求会被发往错误的路径,或者干脆失败。名为models/text-embedding-004的模型会在预测 URL 上多出一段路径,而不是用于指定模型;?或空格则会产生HTTP 500,错误日志中记录invalid characters found in path——请求根本没有被发出去。现在模型名会被转义成单个路径段。 - 修复问题:当 LLM 上游在流式响应已经有一部分发送给客户端之后断开连接时,网关仍会尝试把已经提交的
HTTP 200改成500,而响应一旦开始返回,状态码是改不了的。客户端拿到的仍然是被截断的流,但错误日志会被attempt to set status 500 via ngx.exit after sending out the response status 200刷屏;并且 AI Proxy Multi 会把这次失败视为可重试,从而在客户端已经收到部分内容之后,再向第二个实例发出一次会产生费用的请求。现在流就在中断处结束——不会补发协议的结束标记,因此客户端可以通过缺失的[DONE]察觉到内容被截断——出问题的上游连接也会被关闭,而不是放回连接池。
- 修复问题:使用 Vertex AI 提供方时,
- AI AWS Content Moderation 和 AI Aliyun Content Moderation
- 修复问题:被网关自身的
max_response_bytes或max_stream_duration_ms限制截断的流式响应,会被补上一个表示结束的事件,于是客户端会把一段被截断的回答当作模型已经完整作答。现在只有真正正常结束的流才会补发该结束事件。
- 修复问题:被网关自身的
- Traffic Label
- 修复问题:在配置了
ipmatch规则的路由上,编 译后的匹配器被存进了插件自身的配置中,因此从第一个匹配的请求开始,该路由就再也无法被序列化为 JSON。数据面 control API 的GET /v1/routes会失败,info日志级别下的路由 dump 为空,匹配的请求还会记录failed to encode: Cannot serialise table: excessively sparse array。
- 修复问题:在配置了
- AWS Lambda、Azure Functions 和 OpenFunction
- 修复问题:不带路径的
function_uri(例如末尾没有斜杠的https://xxx.lambda-url.us-east-1.on.aws)会产生请求目标为空的请求,严格的函数端点会以HTTP 400 Bad Request拒绝它。现在这类请求会被发往/。此外,状态码大于等于400的函数响应现在会以warn级别记录其状态码和响应体;此前错误日志中只有exits with http status code 403,看不出任何原因。
- 修复问题:不带路径的
数据面
- 修复问题:配置了证书校验并提供了自己的 CA 证书的 HTTPS 上游,即便上游证书确实由该 CA 签发,每个请求也都会失败,返回
HTTP 502,错误日志中记录upstream SSL certificate verify error: (20:unable to get local issuer certificate)。原因是对于只提供了 CA 证书、没有同时提供客户端证书的上游,信任库从来没有被真正应用。现在这类上游可以正常建连。 - 修复问题:
grpcs上游完全忽略了它的证书校验配置,因此无论上游证书由哪个 CA 签发都会被接受。这些配置被分发 gRPC 流量的内部跳转丢弃了,而且上游证书本来也是拿错误的名称去校验的。现在grpcs与https一样会真正执行校验并使用所配置的 CA 证书,同时按上游主机名核对证书。启用了校验、但证书无法回溯到所配置的 CA、或者证书的 subject alternative name 未覆盖上游主机名的grpcs上游,此前可以连通,现在会返回HTTP 502;升级前请先检查这类上游。 - 修复问题:两个上游可能共用同一份解析后的 CA 证书信任库,导致某个上游被用另一个上游的 CA 证书去校验。信任库现在以 CA 证书本身作为缓存键。
- 修复问题:网关 worker 在关闭多路复用的上游连接时可能崩溃,因为连接的日志对象所指向的内存已经先被释放。这个问题在实际使用中通过 Dubbo Proxy 插件触发,它使用的正是多路复用的上游连接。
- 修复问题:当
conf/apisix.uid对运行用户不可写时(离线包出厂即是这种形态),网关每次启动都会以 error 级别记录failed to open file[/usr/local/apisix//conf/apisix.uid] for writing。实例 ID 本身读取正确、实例也正常注册,功能并没有出问题,但这些行在排查时看起来像是真的故障。现在只有在确实需要持久化一个 ID 时才会写文件。 - 修复问题:数据面 control API 的
GET /v1/healthcheck在本应返回数组的位置返回了空 JSON 对象——配置了checks但尚未被使用的上游返回"nodes": {},没有任何健康检查在运行时整个结果返回{}。两者现在都返回[]。
控制面
- 修复问题:在 PostgreSQL 上从 3.8.x 直接升级时,数据库迁移刚一完成,控制面就会崩溃,报出
ERROR: cached plan must not change result type和panic: init ETCD custom_plugins for gateway groups failed。原因是某张表在迁移前被读过一次、迁移后又被读了一次,复用了按旧表结构准备好的语句。现在迁移所使用的连接会在迁移结束后被丢弃,那些语句也随之失效。该问题只影响 PostgreSQL,且只在从低于 3.9.2 的版本升级时出现。 - 修复问题:运行「只发数据面的 hotfix 构建」的网关会被按错误的版本判定。上报的版本与控制面版本只在预发布后缀上不同的网关——例如 3.10.7 控制面下的
3.10.7-patch.1——会被显示为 PartiallyCompatible 并带上建议升级的提示;而且只要它的兼容性报告中出现一条 error 级别的条目,就会被判为 Incompatible 并触发「网关实例需要升级」的横幅,而配置完全相同、运行正式版本的网关则保持 Compatible。现在这类构建会按它所基于的正式版本判定,并且两个方向都适用:hotfix 版本的控制面也不会再对运行正式版本的网关做出同样的误判。 - 修复问题:查询网关实例时既没有带上它所属的网关组,也没有对它的运行记录排序,因此重启过的实例会被一条已经不存在的运行记录代为回答,且这种情况最长可以持续七天。兼容性问题接口返回的报告与同一屏上并排展示的摘要相互矛盾,并且永远不会收敛;删除网关实例时,可能会因为一条过期的运行记录而放行离线校验,从而删掉一个仍然在线、仍然返回
HTTP 200的网关;此外,当同一个实例 ID 同时存在于两个网关组时,数据面上报的健康检查状态可能被归到错误的网关组下。 - 修复问题:当 Prometheus 返回给控制面的内容不是 JSON 时(例如带认证的代理返回了一个 HTML 的
401页面),Dashboard 的监控页面和开发者门户的指标接口会以HTTP 500和invalid character '<' looking for beginning of value失败,完全看不出真正的原因。现在这类响应会被报告为HTTP 502,消息中给出上游的状态,例如prometheus returned 401 Unauthorized,响应体的前 256 字节会记入控制面日志而不是返回给客户端。Prometheus 自身返回的 JSON 错误响应仍然原样透传。
控制台(Dashboard)
- 修复问题:分页表格与卡片列表下方的
Results: X–Y of N标签,在每页条数不是默认的 10 时,从第二页开始显示的区间都是错的,因为该区间是按固定的每页条数计算的,而不是按实际使用的每页条数。列表中呈现的数据始终是正确的,出错的只有这个标签。
开发者门户
- 修复问题:对于外部 API 产品,下载 OpenAPI 文档保存下来的文件名始终是
api-1.json或api-1.yaml,而不是根据 API 生成的名称。由网关服务支撑的产品此前已经是正确的。 - 修复问题:在交互式 API 文档查看器的输入框中粘贴 内容(包括 Basic Auth 的凭据输入框)无法生效,或者对换行处理有误,导致粘贴进去的凭据在请求发出前就被丢弃或变形。
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 此前只作用于通过内省校验的 Token。使用授权码流程的路由(即未设置 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 的 Token 会跳过该校验。现在该选项隐含要求该声明必须存在,不带 aud 的 Token 会收到 HTTP 403。
在 bearer_only 模式下且未配置 valid_issuers 时,受信任的 issuer 来自提供方的 discovery 文档;此前该请求失败时网关只记录一条 warning,并在完全没有 issuer 约束的情况下校验 Token。现在会返回 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拒绝。现在两者可以一起使用,数据面会按客户端偏好协商相应的证书。