2019 年的一个 Spring Cloud Gateway 工程,把路由 JSON 放进 Nacos,监听变更后转成 RouteDefinition,再交给 RouteDefinitionWriter。这样可以改变路由而不重新打包,但更新过程必须与网关的可用性一起设计。
以下围绕旧版响应式 Gateway API 解释,不是可以直接复制上线的完整组件。
路由 JSON 怎样对应转发规则
一个路由定义可以写成:
[
{
"id": "example-consumer",
"order": 0,
"uri": "lb://consumer",
"predicates": [
{ "name": "Path", "args": { "pattern": "/consumer/**" } }
],
"filters": [
{ "name": "StripPrefix", "args": { "parts": "1" } }
]
}
]
Path 匹配入口路径,StripPrefix=1 去掉一个路径段;例如 /consumer/name 经过该过滤器变成 /name。lb://consumer 需要匹配版本的服务发现与负载均衡支持,不是普通的主机名替换。Gateway 2.2.9 参考
Nacos 中的 namespace、data ID 和 group 要与客户端一致。JSON 格式正确,也不代表路由目标安全或一定存在。
初始配置和后续变更都要进入同一流程
客户端获取初始文本、注册 Listener 后,两个入口都应进入统一的解析、校验和应用流程,不能初始 getConfig 只打印,等用户下一次发布才真正装载路由。Nacos Java SDK
拉取与监听之间还可能有竞态,因此应按所用 SDK 设计一致性检查,携带配置版本或内容摘要,串行处理重复和乱序变更。
不要先清空,再逐个异步保存
先删全部路由再解析,遇到空配置、解析失败或保存失败时可能失去正常路由。对每条操作分别 subscribe,也不能保证全部完成后才刷新。
对已经解析、验证并计算差异的配置,可以在一个响应式链里串联操作。下面的方法仅示意时序,writer 与 publisher 为已有组件:
Mono<Void> applyValidatedChanges(
List<RouteDefinition> upserts, List<String> obsoleteIds) {
return Flux.fromIterable(upserts)
.concatMap(route -> writer.save(Mono.just(route)))
.thenMany(Flux.fromIterable(obsoleteIds)
.concatMap(id -> writer.delete(Mono.just(id))))
.then(Mono.fromRunnable(() ->
publisher.publishEvent(new RefreshRoutesEvent(this))));
}
List、Flux、Mono 及路由类型需来自匹配依赖。调用方必须订阅或返回该链,并统一处理错误;只构造 Mono 不会自动执行。
这个链保证的是所示操作的先后,不是事务或自动回滚。中途失败仍可能部分生效,需要保存上一个可用版本、记录结果并设计恢复。只管理本组件拥有的动态路由 ID,不能顺手删除静态或其他来源路由。
配置也属于高权限输入
应用前检查空值策略、重复 ID、谓词、过滤器、URI 协议与允许的目标;拒绝无效版本时保留可用配置。多实例还要观测各自应用版本,而不是只看到 Nacos 发布成功。
动态路由应限制配置编辑权限和可转发目标,避免成为越权访问内部服务的入口。刷新事件只是流程的一环,不替代配置校验、失败恢复和实际转发验证。