You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为HttpClientFactory中使用的DelegatingHandler添加动态参数

解决方案:将Client ID传递到HttpRequestMessage以实现Token刷新重试

要解决Handler中无法获取Client ID的问题,核心是将Client ID与每个HttpRequestMessage绑定,推荐使用.NET 5+提供的HttpRequestOptions(类型安全、不会被发送到目标服务器),或兼容旧版本的Properties。以下是具体实现步骤:

1. 传递Client ID到请求选项

修改HttpClientService,不再直接设置HttpClient的全局Authorization头(避免并发冲突),而是将Client ID存入请求选项,并在每个请求中单独设置初始Token:

internal class HttpClientService
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly ITokenService _tokenService;

    public HttpClientService(IHttpClientFactory httpClientFactory, ITokenService tokenService)
    {
        _httpClientFactory = httpClientFactory;
        _tokenService = tokenService;
    }

    public async Task<HttpResponseMessage> SendRequestAsync(string clientId, HttpRequestMessage request, CancellationToken cancellationToken = default)
    {
        var client = _httpClientFactory.CreateClient("BasicClient");
        // 将Client ID存入请求选项(类型安全,仅在应用内部传递)
        request.Options.Set("ClientId", clientId);
        
        // 设置初始Token
        var token = await _tokenService.GetTokenAsync(clientId);
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        
        return await client.SendAsync(request, cancellationToken);
    }
}

2. 在TokenFreshnessHandler中获取Client ID并刷新Token

修正Handler中的判断逻辑(仅在收到401响应时刷新),并从请求选项中提取Client ID:

public class TokenFreshnessHandler : DelegatingHandler
{
    private readonly ITokenService _tokenService;

    // 通过DI注入Token获取服务
    public TokenFreshnessHandler(ITokenService tokenService)
    {
        _tokenService = tokenService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);

        // 仅在收到401未授权响应时刷新Token并重试
        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            // 从请求选项中获取Client ID
            if (request.Options.TryGetValue(new HttpRequestOptionsKey<string>("ClientId"), out var clientId))
            {
                // 获取新Token
                var newToken = await _tokenService.GetTokenAsync(clientId);
                // 重置请求的Authorization头
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", newToken);
                
                // 重试请求
                response = await base.SendAsync(request, cancellationToken);
            }
        }
        return response;
    }
}

3. 正确注册依赖

确保Handler和相关服务被DI容器正确注册:

// 注册Token服务(根据你的实际实现调整)
services.AddScoped<ITokenService, TokenService>();
// 注册自定义Handler
services.AddScoped<TokenFreshnessHandler>();

// 配置HttpClient
services.AddHttpClient("BasicClient")
    .AddPolicyHandler(GetRetryPolicy())
    .AddHttpMessageHandler<TokenFreshnessHandler>();

关键注意事项

  • 避免全局Header并发问题:不要修改HttpClient.DefaultRequestHeaders,改为在每个HttpRequestMessage中单独设置Authorization头,避免多请求同时修改全局头的冲突。
  • 重试策略与Handler的顺序:确保AddHttpMessageHandler在AddPolicyHandler之后(Handler链从内到外执行),让Token刷新逻辑先于重试策略生效,避免重复重试。
  • 兼容旧版本.NET:如果使用.NET Core 3.1及更早版本,可替换HttpRequestOptions为request.Properties["ClientId"] = clientId,在Handler中通过request.Properties.TryGetValue("ClientId", out var clientIdObj)提取。

内容的提问来源于stack exchange,提问作者user14101378

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 18:35:00