MoneyTree.Configuration 1.0.4
MoneyTree.Configuration 配置中心客户端
📋 概述
MoneyTree.Configuration 提供微服务配置中心客户端能力,支持远程配置拉取、热更新(SSE 推送 + 客户端按需拉取)、多种配置中心后端(Nacos / Apollo / Consul / 本地文件 / 数据库),以及 HMAC 自动签名安全保障。
| 属性 | 说明 |
|---|---|
| NuGet 包 | MoneyTree.Configuration |
| 外部依赖 | MoneyTree.Core |
| 定位 | 微服务启动时自动加载远程配置 |
| 版本 | 1.0.2 |
🏗️ 项目文件结构
MoneyTree.Configuration/
├── MoneyTree.Configuration.csproj
├── GlobalUsings.cs
├── Abstractions/
│ ├── IConfigurationCenterClient.cs # 配置中心客户端接口
│ ├── IRemoteConfigurationClient.cs # 远程配置客户端接口
│ └── IConfigurationWatcher.cs # 配置变更监听接口
├── Core/
│ ├── ConfigurationCenterOptions.cs # 配置中心选项(含 AppId/AppSecret)
│ ├── ConfigurationCenterClient.cs # 配置中心客户端实现
│ ├── ConfigurationContext.cs # 配置上下文
│ └── SseConfigurationWatcher.cs # SSE 配置监听器
├── Providers/
│ ├── DefaultConfigurationProvider.cs # 默认配置提供者
│ └── HttpConfigurationProvider.cs # HTTP 配置提供者
├── Extensions/
│ ├── ConfigurationCenterBuilder.cs # 流畅配置构造器
│ ├── HostingExtensions.cs # 主机启动扩展
│ └── HmacAuthExtensions.cs # HMAC 自动签名扩展
├── Security/
│ └── HmacAuthHandler.cs # HMAC 签名处理器(5段格式,与框架对齐)
└── Caching/
└── ConfigurationCache.cs # 配置缓存
🔄 架构设计
通信模型
SSE 推送作为配置中心客户端与配置中心服务端之间的核心通信协议,采用 "服务端只推送变更信号,客户端按需拉取最新配置" 的架构模式:
┌─────────────────────┐ SSE 长连接 ┌─────────────────────┐
│ 配置中心服务端 │ ◄═══════════════════════════ │ 微服务客户端 │
│ │ │ │
│ 1. 管理员修改配置 │ │ 1. 启动时拉取全量配置 │
│ 2. 存储新版本 │ ──── SSE: 配置已变更 ──────→ │ 2. 建立 SSE 长连接 │
│ 3. 通知所有 SSE 客户端 │ │ 3. 收到通知后拉取配置 │
│ │ ←──── HTTP GET 拉取配置 ───── │ 4. 更新本地 IConfig │
│ 4. 响应配置请求 │ ──── 返回最新配置 ─────────→ │ 5. 继续监听 SSE │
└─────────────────────┘ └─────────────────────┘
所有 HTTP 请求(拉取配置 + SSE 连接)自动携带 HMAC-SHA256 签名头,无需业务代码手动处理。
关键设计原则
| 原则 | 说明 |
|---|---|
| 仅推送变更信号 | SSE 只推送 {"type": "config_changed", "version": 123},不传输配置内容 |
| 客户端按需拉取 | 收到信号后,客户端通过 HTTP GET 主动拉取最新配置 |
| 启动全量拉取 | 应用启动时通过 HTTP GET 拉取完整配置,然后建立 SSE 长连接 |
| 断线自动重连 | SSE 支持 Last-Event-ID 机制,断线重连后自动补发变更通知 |
| 拉取失败降级 | HTTP GET 失败时使用本地缓存配置 |
| HMAC 自动签名 | AppSecret 非空时,所有请求自动携带 HMAC 签名头 |
🚀 快速开始
客户端连接(自动 HMAC 签名)
// 微服务 Program.cs
using MoneyTree.Configuration.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMoneyTreeConfigurationCenter(c =>
{
c.WithServerAddress("http://config-center:5000")
.WithAppId("order-service")
.WithAppSecret("your-app-secret-here") // 配置后自动启用 HMAC 签名
.WithEnvironmentName("Production");
});
var app = builder.Build();
app.Run();
HMAC 自动签名:
AddMoneyTreeConfigurationCenter内部调用AddHmacAuth扩展方法,当AppSecret非空时自动为 HttpClient 注册HmacAuthHandler,所有请求自动携带X-App-Id/X-Timestamp/X-Nonce/X-Sign签名头。签名格式与框架HmacAuthMiddleware完全对齐(5 段)。
🔐 HMAC 自动签名
签名格式(5 段,与框架完全对齐)
StringToSign = HTTPMethod + "\n" + Accept + "\n" + PathAndQuery + "\n" + Timestamp + "\n" + Nonce
Signature = Base64(HMAC-SHA256(AppSecret, StringToSign))
HmacAuthHandler
MoneyTree.Configuration.Security.HmacAuthHandler 是自包含的 DelegatingHandler,不依赖 MoneyTree.Web,确保客户端包保持轻量。
- DI 注入:通过
AddHmacAuth(options)扩展方法自动注册到 HttpClient 管道 - 直接实例化:支持通过
ConfigurationCenterOptions直接构造(供IConfigurationSource构建阶段使用) - 启动阶段签名:
ConfigurationCenterProvider在IConfiguration构建阶段拉取配置时也自动签名
AddHmacAuth 扩展方法
/// 为 HttpClient 添加 HMAC 自动签名
services.AddHttpClient<IRemoteConfigurationClient, HttpConfigurationProvider>(...)
.AddHmacAuth(options); // options 为 ConfigurationCenterOptions
当 AppSecret 为空时跳过签名(兼容免认证部署场景)。
📋 配置提供者
| 提供者 | 适用场景 | 特点 |
|---|---|---|
| Consul | 中小团队、私有部署 | 成熟稳定,社区活跃 |
| Nacos | 国内主流,阿里云生态 | 服务发现 + 配置中心一体化 |
| Apollo | 国内企业级配置中心 | 功能强大,权限管理完善 |
| Database | 自建配置中心 | 灵活可控,与现有系统集成 |
| 本地文件 | 开发环境和离线兜底 | 零依赖,快速启动 |
📊 配置优先级
配置加载遵循严格的优先级顺序:
环境变量 > 远程配置中心 > appsettings.{Environment}.json > appsettings.json > 框架默认值
高优先级的配置值会覆盖低优先级的同名配置项。
💾 配置缓存
配置中心客户端内置缓存机制:
| 场景 | 行为 |
|---|---|
| 首次启动 | HTTP GET 拉取全量配置,写入本地缓存 |
| 收到 SSE 通知 | HTTP GET 拉取增量配置,更新缓存 |
| 拉取失败 | 使用本地缓存中的配置作为降级方案 |
| 应用重启 | 优先读取本地缓存,随后异步更新 |
No packages depend on MoneyTree.Configuration.
.NET 10.0
- MoneyTree.Core (>= 1.0.4)
- Microsoft.Extensions.Configuration (>= 10.0.10)
- Microsoft.Extensions.Configuration.Json (>= 10.0.10)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Http (>= 10.0.10)