XiHan.Framework.Configuration.Nacos
configuration.remote@1 的 Nacos Provider:直接调用 Nacos 的 HTTP 配置接口取整份文档,按内容 MD5 长轮询,不依赖 Nacos SDK。用 Nacos 做配置中心的应用引用本包。
| 项 | 内容 |
|---|---|
| 包 ID | XiHan.Framework.Configuration.Nacos |
| 环层 | Ring 3(实现) |
| 能力 | 提供 configuration.remote@1(role: provider);依赖 kernel.hosting@1;可选绑定 nacos(configuration:remote) |
| 特性入口 | NacosConfigurationFeature |
| 配置节 | XiHan:Configuration:Nacos |
| 依赖 | XiHan.Framework.Configuration.Abstractions、XiHan.Framework.Kernel;Microsoft.Extensions.Http |
| AOT | 兼容 |
| 稳定性 | Preview |
概述
本包有两个入口,用在两个时机:
- 配置构建期:
builder.Configuration.AddXiHanNacos(nacosOptions, remoteOptions)按选项自建客户端(NacosConfigurationClient.Create),经工厂重载交给AddXiHanRemoteConfiguration,于是 Nacos 里的文档成为一个配置源,首次同步加载、之后轮询重载;自建的客户端连同它的 HTTP 客户端归这个配置源,配置根释放时一并释放。这一步发生在容器建立之前,绝大多数应用只需要它。 - 运行期:
UseFeature<NacosConfigurationFeature>()从XiHan:Configuration:Nacos读选项,经IHttpClientFactory建客户端,并在本包被选为configuration.remote@1的提供者时登记为IRemoteConfigurationClient,供其他组件按需取文档。
客户端用 Nacos 的 v1 HTTP 配置接口(与 Nacos 2.x 兼容)。命名空间参数是 Nacos 的 dataId,Group 与 Tenant 来自选项。版本是内容的 MD5,取服务端在响应头 Content-MD5 里给出的值,与 Nacos 监听接口的约定一致;knownVersion 非空时先以该 MD5 调监听接口长轮询,服务端报告变化才取整份文档,窗口到期或调用方取消都返回无值。
何时使用
配置放在 Nacos 里、希望改了以后应用不重启就生效时使用。配置在 Kubernetes ConfigMap 里时用宿主自带的挂载目录(XIHAN_CONFIG_PATH)即可,见配置与选项。Apollo、Consul 等其他配置中心没有提供 Provider,需要应用实现 IRemoteConfigurationClient。
安装与启用
dotnet add package XiHan.Framework.Configuration.Nacos --prerelease当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。
using XiHan.Framework.Configuration.Abstractions.Remote;
using XiHan.Framework.Configuration.Nacos;
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.Profiles.Standard;
var builder = WebApplication.CreateBuilder(args);
// 配置构建期:dataId "orders" 挂到 Orders 节下,每 15 秒以已知版本长轮询
builder.Configuration.AddXiHanNacos(
NacosOptions.FromConfiguration(builder.Configuration),
new RemoteConfigurationOptions("orders") { Prefix = "Orders", PollInterval = TimeSpan.FromSeconds(15) });
// 运行期:登记 IRemoteConfigurationClient(只在需要按需取文档时装)
builder.AddXiHan(xihan => xihan.UseStandardProfile().UseFeature<NacosConfigurationFeature>());配置
| 键 | 类型 | 缺省 | 说明 |
|---|---|---|---|
ServerAddresses | string | 无,必填 | 逗号或分号分隔的绝对 http / https 地址,按序尝试;地址的路径是 Nacos 的上下文路径,没有路径时用 /nacos(见下文)。有绑定 nacos 时被绑定的主值覆盖,两者都没有时抛出 ArgumentException |
Group | string | DEFAULT_GROUP | 配置分组 |
Tenant | string | 空(公共命名空间) | Nacos 命名空间 ID |
Username | string | — | 与 Password 都给出时先登录取 accessToken |
Password | string | — | 登录密码 |
Format | Json / Properties | Json | 文档格式,不区分大小写 |
LongPollTimeoutSeconds | 正数 | 30 | 长轮询窗口 |
RequestTimeoutSeconds | 正数 | 10 | 单次请求(取文档、登录)的超时 |
{
"XiHan": {
"Configuration": {
"Nacos": {
"ServerAddresses": "http://nacos-a:8848,http://nacos-b:8848",
"Group": "DEFAULT_GROUP",
"Tenant": "",
"Username": "dev",
"Password": "dev-password",
"Format": "Json",
"LongPollTimeoutSeconds": 30,
"RequestTimeoutSeconds": 10
}
}
}
}服务地址与凭据也可以用绑定提供:绑定的主值覆盖配置里的 ServerAddresses,属性 username / password 各自覆盖 Username / Password(空白不算给出),分组、格式等其余键照读配置节:
{ "XiHan": { "Bindings": { "nacos": { "type": "configuration:remote", "value": "http://localhost:8848", "username": "nacos", "password": "<来自密钥源>" } } } }主要类型
| 类型 | 说明 |
|---|---|
NacosConfigurationFeature | 特性入口;常量 ConnectionBinding = nacos |
NacosConfigurationBuilderExtensions | AddXiHanNacos(options, remote):配置构建期的入口,自建的客户端随配置根释放 |
NacosConfigurationClient | IRemoteConfigurationClient 实现;Create(options, clock) 自建 HTTP 客户端并在释放时关闭,公开构造函数接收外部的 HttpClient(超时应为无限,由本类按请求控制);常量 HttpClientName |
NacosOptions | 选项;FromConfiguration(configuration, binding) 从配置与绑定读取;常量 ConfigurationSection |
NacosConfigFormat | Json、Properties |
NacosDocumentParser | Parse(content, format) 把文档展平成配置键值 |
使用示例
properties 格式的文档挂在根上,并在 Nacos 不可达时继续启动:
builder.Configuration.AddXiHanNacos(
new NacosOptions { ServerAddresses = ["http://localhost:8848"], Format = NacosConfigFormat.Properties },
new RemoteConfigurationOptions("orders.properties")
{
Optional = true,
OnError = static error => Console.Error.WriteLine($"Nacos unavailable: {error.Code}"),
});orders.properties 的内容 orders.limits.max-items=50 展平后是配置键 orders:limits:max-items。
运行期按需取一份文档(装了 NacosConfigurationFeature):
app.MapGet("/config/orders", async (IRemoteConfigurationClient client, CancellationToken ct) =>
{
var fetched = await client.FetchAsync("orders", knownVersion: null, ct);
return fetched.TryGetValue(out var document) && document.TryGetValue(out var value)
? Results.Ok(value.Version)
: Results.NotFound();
});行为与限制
- 格式:
Json要求根是对象,嵌套对象按A:B展平,数组按下标,null保留为空值;Properties把a.b=c展平成a:b,#与!开头的行是注释。文档不合法返回CONFIGURATION_VALIDATION_001。 - 登录:配置了
Username与Password时调用上下文路径下的/v1/auth/login(缺省即/nacos/v1/auth/login)取accessToken,在到期前一分钟续期;响应没有tokenTtl时按 18000 秒计。 - 多地址:每次请求按
ServerAddresses的顺序尝试,连接失败或超时换下一个,全部失败时返回不可达。 - 版本:服务端没有给出
Content-MD5(例如中间的代理去掉了这个头)时,客户端按 Nacos 的算法自己算,即内容按 UTF-8 编码的 MD5(小写十六进制),监听接口照样认得这个版本,长轮询不受影响。 - 上下文路径:地址的路径就是 Nacos 的上下文路径(
server.servlet.contextPath),登录、取配置、监听的接口路径(/v1/auth/login、/v1/cs/configs、/v1/cs/configs/listener)接在它后面;地址没有路径(或只有/)时用 Nacos 的缺省值/nacos,所以http://nacos:8848与http://nacos:8848/nacos等价。Nacos 改了上下文路径时写http://nacos:8848/config;经网关挂在前缀下时把网关前缀连同上下文路径写全,例如网关把/config-center/转发到 Nacos 的根上,就写http://gateway/config-center/nacos。上下文路径设成根(/)的 Nacos 无法用地址表达,不受支持。 - 一致性:通过
Configuration.Conformance的RemoteConfigurationClientConformance(Nacos 2.5.1)。测试需要真实服务,本地可用docker run -d -p 8848:8848 -e MODE=standalone nacos/nacos-server:v2.5.1启动(3.x 镜像默认开启鉴权且 v1 接口不再可用,未验证),设置XIHAN_TEST_NACOS(如http://localhost:8848)后运行,开启鉴权的服务再设XIHAN_TEST_NACOS_USERNAME/XIHAN_TEST_NACOS_PASSWORD。Nacos 3.x 默认开启鉴权且 v1 接口不再可用,未验证。
| 错误码 | 含义 |
|---|---|
CONFIGURATION_NOTFOUND_001 | dataId 不存在(Nacos 返回 404) |
CONFIGURATION_UNAVAILABLE_001 | 不可达、超时、登录失败或非 2xx 响应 |
CONFIGURATION_VALIDATION_001 | 文档不是声明的格式 |
相关
- 配置与选项
- Configuration.Abstractions
- 规范:RFC-0014《远程配置与密钥》、ADR-0019
