Nacos 3.2.4 升级后老客户端报 501 no such api 的问题处理记录
记录时间:2026-08-31
环境:公司测试(xc/test)Nacos,nacos-server v3.1.1 升 v3.2.4,K8s StatefulSet 2 副本 + 外置 MySQL,Harbor 内网仓库(信创 ARM64)
一、问题现象
前一天刚按漏洞通告把 Nacos 升到 3.2.4,隔天技术找上门:服务 xxx-openApi-service 刷一屏报错,服务发现列表拉不到:
com.alibaba.nacos.api.exception.NacosException: {"status":501,"error":"Not Implemented",
"message":"no such api:GET:/nacos/v1/ns/instance/list","path":"/nacos/v1/ns/instance/list"}
[NA] failed to update serviceName: DEFAULT_GROUP@@xxx-openApi-service
failed to req API:/nacos/v1/ns/instance/list after all servers([nacos-svc.xxx.svc.cluster.local:8848]) tried: ErrCode:501
501,Not Implemented,服务端说这接口没了。妈的,升级前好好的,升完就没了。
二、排查过程
第一轮(试错,无效):只开兼容开关。我第一反应是 Nacos 3.x 把 v1 API 默认关了,configmap 里官方模板本来就躺着三行注释掉的开关,把 nacos.core.api.compatibility.client.enabled=true 取消注释,apply,重启。结果不生效,501 原样照刷。我当时写进 configmap 的注释也跟着错了,一并改掉了。
第二轮:翻 3.2.4 源码,找到 501 的出处。我把 alibaba/nacos 的 3.2.4 tag 拉下来 grep,DistroFilter.java 里现成的:
} catch (NoSuchMethodException e) {
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED,
"no such api:" + req.getMethod() + ":" + req.getRequestURI());
}
501 不是开关关出来的,是请求落到一个根本没有映射的路由上抛出来的。也就是说 v1 Controller 不是被关了,是从主包里被删了。开关再怎么写都是对着空气使劲。
第三轮:找到官方把 v1 搬哪去了。3.2.4 源码的规范文档 specs/zh-cn/design/compatibility-deprecation-spec.md 第 10 节写得明明白白:从 3.2.0 起,v1/v2 HTTP API 不在默认发行包里了,整体迁到独立仓库 nacos-group/nacos-api-legacy-adapter,装不装由用户自己决定。官方升级文档里也有一节对着说这事,见 旧版HTTP API移除说明 (Nacos 3.2.0+):
重大变更:从 Nacos 3.2.0 开始,旧版 v1 和 v2 HTTP API 已从 Nacos 主仓库中移除。旧版的 v1 和 v2 HTTP API 不再包含在默认的 Nacos server 发行版中。这些 API 已迁移到单独的旧版适配器模块中。受影响的 API:所有 v1 REST APIs(例如 /nacos/v1/ns/instance、/nacos/v1/cs/configs)、所有 v2 REST APIs。
第四轮:验证开关到底谁在读。我把官方发布的 adapter jar 下载下来反编译,ApiCompatibilityConfig 里确实读 nacos.core.api.compatibility.client.enabled(默认 false),但这是 adapter 插件的代码。主包的 CompatibilityHelper 只认另一个 key nacos.core.api.compatibility.enabled,而且那个只管 6 个废弃的 v3 端点(关了返回 410),跟 v1/v2 一毛钱关系没有。
到这里结论锤死了:不装 adapter 插件 jar,光开开关是无效的。我第一轮的方案就栽在这。
三、根因分析
Nacos 3.2.0 起把 v1/v2 HTTP API 从服务端发行包物理移除了,老 HTTP 客户端打的 /nacos/v1/ns/instance/list 等服务端已经不认。而技术侧服务里 nacos-client 版本不齐,用 1.x 的服务走 HTTP 轮询(8848),用 2.x 的服务走 gRPC(9848),所以升级后只有 1.x 那批炸,2.x 的没事。官方给了两条路:迁移到 v3 API 和新客户端(推荐,但业务改造要时间),或者临时装 legacy adapter 把旧端点垫回来。
坑的细节,官方文档 3.4 节那张兼容表还留了个空子:
| Nacos 版本 | 适配器版本 | 兼容性 |
|---|---|---|
| 3.2.0 | 3.2.0 | ✅ 兼容 |
| 3.3.0+ | 匹配 Nacos 版本 | ⚠️ 请检查兼容性 |
我们 server 是 3.2.4,官方却只发了 3.2.0 的 adapter(Release 3.2.0.2,产物名就叫 nacos-api-legacy-adapter-3.2.0.jar),表里没直接给 3.2.4 的答案。我翻了 adapter 的 pom,nacos.version 写的是范围 [3.2.0, 4.0.0),官方声明兼容整个 3.2.x 线,加上实测通过,才敢往上配。将来升 3.3.x 记得回来对这张表。
四、解决方案
不走源码构建那条路(JDK 17 + Maven,还得先编一遍 nacos 主仓库,我们环境编译机是 JDK 11,纯给自己找罪受)。官方 Release 有编译好的 jar,直接塞进镜像:
- 从 nacos-api-legacy-adapter GitHub Releases 下载官方 jar(Release 3.2.0.2,产物名
nacos-api-legacy-adapter-3.2.0.jar,147KB,SHA-2562779587cbb96698c122c03115ab8265ae6bd9221634fad2dde198384e678fa89) - 自建镜像,官方镜像打底,jar COPY 进
/home/nacos/plugins/。启动脚本docker-startup.sh固定-Dloader.path含${BASE_DIR}/plugins,jar 进 classpath 自动加载,一行配置都不用加
FROM harbor.example.com/library/nacos/nacos-server:v3.2.4
LABEL maintainer="ops<ops@example.com>" \
nacos.version="3.2.4" \
custom.legacy-adapter="nacos-api-legacy-adapter-3.2.0"
COPY nacos-api-legacy-adapter-3.2.0.jar /home/nacos/plugins/
- configmap 里
nacos.core.api.compatibility.client.enabled=true保留(adapter 读取它,不装 jar 时它没任何作用)
| 项 | 值 | 说明 |
|---|---|---|
| 镜像 | harbor.example.com/library/nacos/nacos-server:3.2.4-custom | 官方 3.2.4 + adapter jar |
| 插件开关 | nacos.core.api.compatibility.client.enabled=true | 由 adapter 读取,默认 false |
| jar 位置 | /home/nacos/plugins/ | 镜像层 COPY,不碰 PVC |
注意:jar 放镜像里就行,别打 PVC 的主意。PVC 有历史数据,还要加 subPath 挂载编排,纯属给自己加戏。
五、验证
镜像推送后换 tag,滚动完成,进 Pod 一步步验:
# jar 在不在
kubectl -n tools exec nacos-0 -- ls -la /home/nacos/plugins/ | grep legacy
# 路由活没活(带 identity 头)
curl -H "$NACOS_AUTH_IDENTITY_KEY: $NACOS_AUTH_IDENTITY_VALUE" \
"http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=xxx-openApi-service"
响应变化本身就是答案:501 说明路由不存在,403 说明路由在了、被鉴权拦下,200 说明带凭据查询正常。两副本都用报错日志里的真实服务名 xxx-openApi-service 复测过,200。裸 curl 不带凭证会吃 403 access denied,这是环境鉴权开着的正常表现,1.x 客户端本来就带账密,不受影响。
六、注意事项
- 开关必须配 jar。
nacos.core.api.compatibility.client.enabled=true单独开永远无效,主包代码根本不读它。这个结论我第一轮踩进去过,记死了。 - test 回退 3.1.1 能恢复,是因为 3.1.x 主包还带 v1 API。别误以为 3.1.1 也支持这个开关,回退只是绕过了删除点,不是修好了。
- 官方明确表态这是临时方案:不保证后续版本支持、无长期维护计划。业务侧还是得把 1.x 客户端统一升到 2.x/3.x 走 gRPC,之后关掉开关、移除 jar。
七、客户端侧跟进:技术环境 1.4.2 换 2.4.3
开发环境服务端是 2.4.3,双协议并存(v1 HTTP + gRPC),两代客户端可以共存过渡,技术侧不用一次全换,改一个发一个。
先确认服务端 gRPC 端口在听,这一步在 nacos 宿主机上查:
ss -nltp | grep 9848
# LISTEN 0 128 [::]:9848 [::]:* users:(("java",pid=22069,fd=81))
9848 是 2.x 客户端建 gRPC 长连接的端口(主端口 8848 +1000 的固定偏移)。监听着,服务端这关就过了。
pom 里两种写法机制一模一样(从 SCA 的 BOM 里 exclude 掉 nacos-client,再手动钉版本),差别只在钉的版本。客户端版本跟着服务端版本线走,2.4.3 服务端就钉 2.4.3(nacos-client 版本列表),走 gRPC;1.4.2 走 HTTP v1,就是这次 501 炸掉的那类。修复只改一行版本号,结构不动:
<dependencyManagement>
<dependencies>
<!-- spring-cloud-dependencies import 略 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 修复:1.4.2 改成与服务端对齐的 2.4.3 -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.4.3</version>
</dependency>
</dependencies>
</dependencyManagement>
换完用这几个信号确认真的切到了 gRPC:
| 信号 | 命令 / 位置 | 期望 |
|---|---|---|
| 依赖树 | mvn dependency:tree \| grep nacos-client |
只剩一个 2.4.3,不能还有 1.4.2 |
| 应用日志 | 业务应用日志 | 不再有 HostReactor / /v1/ns/instance/list 轮询记录,出现连 9848 的 gRPC 日志 |
| 服务端连接 | ss -tnp \| grep 9848(nacos 宿主) |
出现来自业务应用 IP 的 ESTAB 连接 |
| 控制台 | 服务列表详情 | 该实例客户端版本显示 2.x |
要点:
- 客户端地址配的 8848 不用改,2.x 会自动推导 9848;但应用必须能访问宿主机 9848(同 compose 网络用服务名,跨主机用宿主 IP),有防火墙的放行 9848。
- 2.x 客户端有降级兜底:9848 不通会自动退回 HTTP 模式,不会像 1.4.2 碰 3.x 那样直接死,升级风险低。
- 客户端版本与服务端对齐:2.4.3 服务端就钉 2.4.3(2.4.x 线最新),同版本线是官方推荐组合,不用纠结 2.2.3 还是 2.3.x;将来服务端升 3.x 时客户端再跟着升。
- 清库存用 grep 清单跟踪,把 1.4.2 这个字符串从所有 pom 里消灭掉:
grep -rn "nacos-client" --include="pom.xml" | grep "1\.4\.2"
- 1.4.2 清干净之后,技术环境将来升 3.x 就不用装 legacy adapter,业务面直接 gRPC 平滑过去。