Skip to content

Commit e2163ca

Browse files
author
shiliu
committed
refactor: 完成项目多维度优化与功能完善
本次提交包含多项核心改进: 1. 令牌缓存与OAuth2配置优化:新增配置节常量、DI注入构造函数,修复配置绑定逻辑 2. 弹性策略重构:调整配置结构,添加参数校验与跨选项冲突检查,完善文档与测试 3. 健康检查优化:重构配置路径与继承关系 4. OpenTelemetry增强:新增配置绑定支持,扩展可配置项 5. 文档与测试补充:更新各模块README,新增大量单元测试覆盖配置绑定与参数校验
1 parent 575017f commit e2163ca

18 files changed

Lines changed: 915 additions & 31 deletions

Mud.HttpUtils.Client/HttpClient/Observability/HealthChecksServiceCollectionExtensions.cs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -122,21 +122,10 @@ public sealed class MudHttpHealthChecksOptions
122122

123123
/// <summary>
124124
/// 令牌刷新健康检查配置(含失败状态)。
125+
/// 继承自 <see cref="TokenRefreshHealthCheckOptions"/>,额外包含 <see cref="FailureStatus"/> 属性。
125126
/// </summary>
126-
public sealed class TokenRefreshHealthCheckSettings
127+
public sealed class TokenRefreshHealthCheckSettings : TokenRefreshHealthCheckOptions
127128
{
128-
/// <summary>统计窗口期(秒),默认 300。</summary>
129-
public int WindowSeconds { get; set; } = 300;
130-
131-
/// <summary>告警阈值(0~1),默认 0.2。</summary>
132-
public double DegradedThreshold { get; set; } = 0.2;
133-
134-
/// <summary>临界阈值(0~1),默认 0.5。</summary>
135-
public double CriticalThreshold { get; set; } = 0.5;
136-
137-
/// <summary>最小样本数,默认 5。</summary>
138-
public int MinSampleSize { get; set; } = 5;
139-
140129
/// <summary>失败时返回的健康状态,默认 null(由健康检查内部判定)。</summary>
141130
public HealthStatus? FailureStatus { get; set; }
142131
}

Mud.HttpUtils.Client/HttpClient/Observability/TokenRefreshHealthCheckOptions.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ namespace Mud.HttpUtils.Observability;
88
/// <summary>
99
/// 令牌刷新健康检查选项。
1010
/// </summary>
11-
public sealed class TokenRefreshHealthCheckOptions
11+
public class TokenRefreshHealthCheckOptions
1212
{
13-
/// <summary>配置节点路径。</summary>
14-
public const string SectionName = "TokenRefreshHealthCheck";
13+
/// <summary>
14+
/// 配置节点路径。在 <c>appsettings.json</c> 中位于 <c>MudHttpHealthChecks:TokenRefresh</c> 下。
15+
/// </summary>
16+
public const string SectionName = "MudHttpHealthChecks:TokenRefresh";
1517

1618
/// <summary>
1719
/// 统计窗口期(秒),默认 300 秒(5 分钟)。

Mud.HttpUtils.Client/README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,72 @@ var httpContent = formContent.ToHttpContent(); // FormUrlEncodedContent
214214

215215
> `DefaultFormContent``IFormContent` 的默认实现,将字典数据转换为 `FormUrlEncodedContent`。适用于简单的表单提交场景。
216216
217+
### OAuth2 配置
218+
219+
`OAuth2Options` 用于配置 OAuth2 客户端凭证流程的参数,配置节名称为 `MudHttpOAuth2`
220+
221+
| 属性 | 类型 | 默认值 | 说明 |
222+
| --- | --- | --- | --- |
223+
| `ClientId` | `string` | `""` | 客户端 ID |
224+
| `ClientSecret` | `string` | `""` | 客户端密钥(明文,建议优先使用 `ClientSecretProviderName`|
225+
| `ClientSecretProviderName` | `string?` | `null` | 密钥安全提供程序名称,设置后从 `ISecretProvider` 获取密钥 |
226+
| `TokenEndpoint` | `string` | `""` | 令牌端点 URL |
227+
| `RevocationEndpoint` | `string` | `""` | 令牌撤销端点 URL |
228+
| `IntrospectionEndpoint` | `string` | `""` | 令牌内省端点 URL |
229+
| `RequireHttps` | `bool` | `true` | 是否强制 HTTPS 端点 |
230+
| `ExpirySafetyMarginSeconds` | `int` | `60` | 令牌过期安全边际(秒),提前刷新以避免使用过期令牌 |
231+
232+
> **安全提示**:当同时设置 `ClientSecret``ClientSecretProviderName` 时,`ClientSecretProviderName` 优先生效。建议仅设置其中之一以避免混淆。`AddMudHttpOAuth2FromConfiguration` 会在启动时自动检测此冲突并记录警告日志。
233+
234+
```csharp
235+
// 通过代码配置
236+
services.Configure<OAuth2Options>(options =>
237+
{
238+
options.ClientId = "my-client";
239+
options.ClientSecretProviderName = "vault-provider";
240+
options.TokenEndpoint = "https://auth.example.com/token";
241+
options.ExpirySafetyMarginSeconds = 90;
242+
});
243+
244+
// 或通过 IConfiguration 绑定
245+
services.AddMudHttpOAuth2FromConfiguration(configuration);
246+
```
247+
248+
对应 `appsettings.json`
249+
250+
```json
251+
{
252+
"MudHttpOAuth2": {
253+
"ClientId": "my-client",
254+
"ClientSecretProviderName": "vault-provider",
255+
"TokenEndpoint": "https://auth.example.com/token",
256+
"RevocationEndpoint": "https://auth.example.com/revoke",
257+
"IntrospectionEndpoint": "https://auth.example.com/introspect",
258+
"RequireHttps": true,
259+
"ExpirySafetyMarginSeconds": 90
260+
}
261+
}
262+
```
263+
264+
### 用户令牌缓存配置
265+
266+
`UserTokenCacheOptions` 用于配置用户令牌缓存的容量、过期和清理策略,配置节名称为 `MudHttpUserTokenCache`
267+
268+
| 属性 | 类型 | 默认值 | 说明 |
269+
| --- | --- | --- | --- |
270+
| `SizeLimit` | `int` | `10000` | 缓存容量限制(用户数量) |
271+
| `ExpireThresholdSeconds` | `int` | `300` | 令牌过期提前量(秒),即将过期时触发刷新 |
272+
| `CleanupIntervalSeconds` | `int` | `300` | 缓存清理间隔(秒) |
273+
| `SlidingExpirationSeconds` | `int` | `3600` | 滑动过期时间(秒),未访问则自动移除 |
274+
| `CompactionPercentage` | `double` | `0.2` | 缓存压缩百分比(达容量限制时按此比例淘汰) |
275+
276+
```csharp
277+
// 通过 IConfiguration 绑定
278+
services.AddMudHttpUserTokenCacheFromConfiguration(configuration);
279+
```
280+
281+
> `UserTokenManagerBase` 支持通过 `IOptions<UserTokenCacheOptions>` 从 DI 注入缓存配置。子类构造函数可接收 `IOptions<UserTokenCacheOptions>` 参数,确保通过 `AddMudHttpUserTokenCacheFromConfiguration` 绑定的配置生效。
282+
217283
### 令牌恢复配置
218284

219285
`TokenRecoveryOptions` 用于控制 401 响应时的自动令牌刷新与重试行为,配置节名称为 `MudHttpTokenRecovery`

Mud.HttpUtils.Client/ServiceCollectionExtensions.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,9 @@ public static IServiceCollection AddMudHttpOAuth2FromConfiguration(
674674
throw new ArgumentNullException(nameof(configuration));
675675

676676
services.Configure<OAuth2Options>(configuration.GetSection(sectionPath));
677+
// 注册后置配置器,在选项绑定后检查 ClientSecret 与 ClientSecretProviderName 的互斥冲突
678+
services.TryAddSingleton<IPostConfigureOptions<OAuth2Options>>(sp =>
679+
new OAuth2OptionsPostConfigure(sp.GetService<ILogger<OAuth2OptionsPostConfigure>>()));
677680
return services;
678681
}
679682

@@ -704,13 +707,13 @@ public static IServiceCollection AddMudHttpTokenRecoveryFromConfiguration(
704707
/// </summary>
705708
/// <param name="services">服务集合。</param>
706709
/// <param name="configuration">配置实例。</param>
707-
/// <param name="sectionPath">配置节点路径,默认 <c>"MudHttpUserTokenCache"</c>。</param>
710+
/// <param name="sectionPath">配置节点路径,默认 <see cref="UserTokenCacheOptions.SectionName"/>。</param>
708711
/// <returns>服务集合(链式调用)。</returns>
709712
/// <exception cref="ArgumentNullException">参数为 null 时抛出。</exception>
710713
public static IServiceCollection AddMudHttpUserTokenCacheFromConfiguration(
711714
this IServiceCollection services,
712715
IConfiguration configuration,
713-
string sectionPath = "MudHttpUserTokenCache")
716+
string sectionPath = UserTokenCacheOptions.SectionName)
714717
{
715718
if (services == null)
716719
throw new ArgumentNullException(nameof(services));
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// -----------------------------------------------------------------------
2+
// 作者:Mud Studio 版权所有 (c) Mud Studio 2026
3+
// Mud.HttpUtils 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
4+
// 本项目主要遵循 MIT 许可证进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 文件。
5+
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!
6+
// -----------------------------------------------------------------------
7+
8+
using Microsoft.Extensions.Logging;
9+
using Microsoft.Extensions.Logging.Abstractions;
10+
using Microsoft.Extensions.Options;
11+
12+
namespace Mud.HttpUtils;
13+
14+
/// <summary>
15+
/// OAuth2 选项的后置配置器,在选项绑定后检查 <see cref="OAuth2Options.ClientSecret"/>
16+
/// 与 <see cref="OAuth2Options.ClientSecretProviderName"/> 的互斥冲突并记录警告日志。
17+
/// </summary>
18+
internal sealed class OAuth2OptionsPostConfigure : IPostConfigureOptions<OAuth2Options>
19+
{
20+
private readonly ILogger<OAuth2OptionsPostConfigure> _logger;
21+
22+
public OAuth2OptionsPostConfigure(ILogger<OAuth2OptionsPostConfigure>? logger)
23+
{
24+
_logger = logger ?? NullLogger<OAuth2OptionsPostConfigure>.Instance;
25+
}
26+
27+
/// <inheritdoc />
28+
public void PostConfigure(string? name, OAuth2Options options)
29+
{
30+
if (options == null)
31+
return;
32+
33+
var warning = options.GetConflictWarning();
34+
if (warning != null)
35+
{
36+
_logger.LogWarning("{Warning}", warning);
37+
}
38+
}
39+
}

Mud.HttpUtils.Client/TokenManager/UserTokenCacheOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ namespace Mud.HttpUtils;
1212
/// </summary>
1313
public class UserTokenCacheOptions
1414
{
15+
/// <summary>
16+
/// 配置节的名称。
17+
/// </summary>
18+
public const string SectionName = "MudHttpUserTokenCache";
19+
1520
/// <summary>
1621
/// 默认缓存容量限制(用户数量)。
1722
/// </summary>

Mud.HttpUtils.Client/TokenManager/UserTokenManagerBase.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// -----------------------------------------------------------------------
77

88
using System.Collections.Concurrent;
9+
using Microsoft.Extensions.Options;
910

1011
namespace Mud.HttpUtils;
1112

@@ -46,6 +47,16 @@ protected UserTokenManagerBase(UserTokenCacheOptions? cacheOptions) : this(null,
4647
{
4748
}
4849

50+
/// <summary>
51+
/// 初始化用户令牌管理器基类,从 DI 注入缓存配置选项。
52+
/// 使用此构造函数时,<see cref="UserTokenCacheOptions"/> 将从 <see cref="IOptions{TOptions}"/> 获取,
53+
/// 确保通过 <c>AddMudHttpUserTokenCacheFromConfiguration</c> 绑定的配置能够生效。
54+
/// </summary>
55+
/// <param name="cacheOptions">从 DI 注入的缓存配置选项。为 null 时使用默认配置。</param>
56+
protected UserTokenManagerBase(IOptions<UserTokenCacheOptions>? cacheOptions) : this(null, cacheOptions?.Value)
57+
{
58+
}
59+
4960
/// <summary>
5061
/// 初始化用户令牌管理器基类,使用指定的令牌缓存和缓存配置选项。
5162
/// </summary>

Mud.HttpUtils.OpenTelemetry/MudHttpOpenTelemetryExtensions.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目开发而产生的一切法律纠纷和责任,我们不承担任何责任!
66
// -----------------------------------------------------------------------
77

8+
using Microsoft.Extensions.Configuration;
89
using Microsoft.Extensions.DependencyInjection;
910
using OpenTelemetry;
1011
using OpenTelemetry.Exporter;
@@ -22,7 +23,7 @@ namespace Mud.HttpUtils.OpenTelemetry;
2223
/// Mud.HttpUtils OpenTelemetry 适配包的 DI 扩展方法。
2324
/// </summary>
2425
/// <remarks>
25-
/// <para>通过 <see cref="AddMudHttpOpenTelemetry"/> 一键启用 Mud.HttpUtils 的分布式追踪与指标采集,
26+
/// <para>通过 <see cref="AddMudHttpOpenTelemetry(IServiceCollection, Action{MudHttpOpenTelemetryOptions}?)"/> 一键启用 Mud.HttpUtils 的分布式追踪与指标采集,
2627
/// 并关联 .NET HttpClient 内置的 <c>System.Net.Http</c> ActivitySource。</para>
2728
/// <para>默认导出至本地 OTLP gRPC 端点(<c>http://localhost:4317</c>),
2829
/// 通过 <see cref="MudHttpOpenTelemetryOptions.OtlpEndpoint"/> 自定义。</para>
@@ -31,6 +32,48 @@ namespace Mud.HttpUtils.OpenTelemetry;
3132
/// </remarks>
3233
public static class MudHttpOpenTelemetryExtensions
3334
{
35+
/// <summary>
36+
/// 一键开启 Mud.HttpUtils 的 OpenTelemetry 追踪与指标采集,从 <see cref="IConfiguration"/> 绑定选项。
37+
/// </summary>
38+
/// <param name="services">服务集合。</param>
39+
/// <param name="configuration">配置实例,用于绑定 <see cref="MudHttpOpenTelemetryOptions"/>。</param>
40+
/// <param name="sectionPath">配置节点路径,默认 <c>"MudHttpOpenTelemetry"</c>。</param>
41+
/// <param name="configure">可选的附加配置委托,在配置绑定之后执行,可覆盖绑定值。</param>
42+
/// <returns>返回 <see cref="OpenTelemetryBuilder"/>,便于调用方继续追加配置。</returns>
43+
/// <exception cref="ArgumentNullException"><paramref name="services"/> 或 <paramref name="configuration"/> 为 null。</exception>
44+
/// <example>
45+
/// appsettings.json:
46+
/// <code>
47+
/// {
48+
/// "MudHttpOpenTelemetry": {
49+
/// "ServiceName": "my-service",
50+
/// "SamplingRatio": 0.1,
51+
/// "OtlpEndpoint": "http://otel-collector:4317",
52+
/// "EnableLogging": true
53+
/// }
54+
/// }
55+
/// </code>
56+
/// 代码:
57+
/// <code>
58+
/// builder.Services.AddMudHttpOpenTelemetry(builder.Configuration);
59+
/// </code>
60+
/// </example>
61+
public static OpenTelemetryBuilder AddMudHttpOpenTelemetry(
62+
this IServiceCollection services,
63+
IConfiguration configuration,
64+
string sectionPath = "MudHttpOpenTelemetry",
65+
Action<MudHttpOpenTelemetryOptions>? configure = null)
66+
{
67+
if (services is null) throw new ArgumentNullException(nameof(services));
68+
if (configuration is null) throw new ArgumentNullException(nameof(configuration));
69+
70+
var options = new MudHttpOpenTelemetryOptions();
71+
configuration.GetSection(sectionPath).Bind(options);
72+
configure?.Invoke(options);
73+
74+
return AddMudHttpOpenTelemetryCore(services, options);
75+
}
76+
3477
/// <summary>
3578
/// 一键开启 Mud.HttpUtils 的 OpenTelemetry 追踪与指标采集。
3679
/// </summary>
@@ -62,6 +105,14 @@ public static OpenTelemetryBuilder AddMudHttpOpenTelemetry(
62105
var options = new MudHttpOpenTelemetryOptions();
63106
configure?.Invoke(options);
64107

108+
return AddMudHttpOpenTelemetryCore(services, options);
109+
}
110+
111+
private static OpenTelemetryBuilder AddMudHttpOpenTelemetryCore(
112+
IServiceCollection services,
113+
MudHttpOpenTelemetryOptions options)
114+
{
115+
65116
// 配置 Resource:service.name / service.version / deployment.environment(OTel 规范必需)
66117
var builder = services.AddOpenTelemetry()
67118
.ConfigureResource(r => r

Mud.HttpUtils.OpenTelemetry/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,48 @@ using var provider = services.BuildServiceProvider();
6060
|------|------|--------|------|
6161
| `EnableTracing` | `bool` | `true` | 是否启用分布式追踪 |
6262
| `EnableMetrics` | `bool` | `true` | 是否启用指标采集 |
63+
| `EnableLogging` | `bool` | `false` | 是否启用 OTLP 日志导出(向后兼容;依赖 .NET 8+ 的 ILogger 集成) |
6364
| `EnableHttpClientInstrumentation` | `bool` | `true` | 关联 .NET HttpClient 内置 ActivitySource |
6465
| `EnableAspNetCoreInstrumentation` | `bool` | `true` | 启用 ASP.NET Core 入站请求 Instrumentation(控制台应用无效) |
6566
| `OtlpEndpoint` | `Uri?` | `http://localhost:4317` | OTLP 导出端点,`null` 表示不配置 OTLP 导出器 |
6667
| `OtlpExportProtocol` | `OtlpExportProtocol` | `Grpc` | OTLP 导出协议(`Grpc``HttpProtobuf`|
6768
| `UseShortExporterTimeout` | `bool` | `false` | 是否使用 5 秒短超时(开发调试用) |
69+
| `ServiceName` | `string` | `"Mud.HttpUtils.Application"` | OTel Resource 属性 `service.name` |
70+
| `ServiceVersion` | `string` | `MudHttpActivitySource.Version` | OTel Resource 属性 `service.version` |
71+
| `DeploymentEnvironment` | `string` | `"production"` | OTel Resource 属性 `deployment.environment` |
72+
| `SamplingRatio` | `double` | `1.0` | 采样比率(0.0~1.0),生产环境建议 0.1~0.3 |
73+
| `ExportBatchSize` | `int?` | `null` | OTLP 批量导出批量大小,`null` 使用 SDK 默认值(512) |
74+
| `ExportIntervalMilliseconds` | `int?` | `null` | OTLP 批量导出间隔(毫秒),`null` 使用 SDK 默认值(5000ms) |
75+
| `OtlpHeaders` | `IDictionary<string, string>?` | `null` | 自定义 OTLP Headers(如认证头) |
6876
| `ConfigureTracing` | `Action<TracerProviderBuilder>?` | `null` | 自定义追踪配置委托,在 Mud 默认配置之后执行 |
6977
| `ConfigureMetrics` | `Action<MeterProviderBuilder>?` | `null` | 自定义指标配置委托,在 Mud 默认配置之后执行 |
78+
| `ConfigureLogging` | `Action<LoggerProviderBuilder>?` | `null` | 自定义日志配置委托,在 Mud 默认配置之后执行 |
79+
80+
### 从 IConfiguration 绑定
81+
82+
除代码配置外,还支持从 `appsettings.json` 绑定选项:
83+
84+
```csharp
85+
builder.Services.AddMudHttpOpenTelemetry(builder.Configuration);
86+
```
87+
88+
对应 `appsettings.json`
89+
90+
```json
91+
{
92+
"MudHttpOpenTelemetry": {
93+
"ServiceName": "my-service",
94+
"SamplingRatio": 0.1,
95+
"OtlpEndpoint": "http://otel-collector:4317",
96+
"EnableLogging": true,
97+
"OtlpHeaders": {
98+
"Authorization": "Bearer my-token"
99+
}
100+
}
101+
}
102+
```
103+
104+
> 也可同时使用配置绑定和代码配置:`AddMudHttpOpenTelemetry(builder.Configuration, configure: options => { ... })`,代码配置在配置绑定之后执行,可覆盖绑定值。
70105
71106
### 高级配置示例
72107

0 commit comments

Comments
 (0)