.NET Core中如何从Program.cs向HttpClient添加请求头(最优方案)
问题描述
现有一个注册HttpClient及依赖的扩展类InternalAdminServiceRegister,希望从Program.cs中传递一个请求头参数给该HttpClient,目标是通过AddHttpMessageHandler实现,而非直接在HttpClient配置中添加默认请求头的方式。
原扩展类代码:
public static class InternalAdminServiceRegister { public const string DefaultConfigSectionName = "InternalApisOptions:Admin"; public static IServiceCollection AddAdminInternalServices( this IServiceCollection services, IConfiguration configuration, string configSectionName = DefaultConfigSectionName) { services.Configure<AdminOptions>(configuration.GetSection(configSectionName)); services.AddHttpClient<IInternalAdminService, InternalAdminService>((sp, client) => { var options = sp.GetRequiredService<IOptions<AdminOptions>>().Value; client.BaseAddress = new Uri(options.ServiceUrl); client.Timeout = TimeSpan.FromMilliseconds(options.TimeoutMs); }).AddPolicyHandler(GetCircuitBreakerPolicy()); return services; } private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy() => HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync(handledEventsAllowedBeforeBreaking: 5, durationOfBreak: TimeSpan.FromSeconds(7)); }
Program.cs调用代码:
var builder = MtsHost.CreateWebApplication(args); builder.Services.AddAdminInternalServices(builder.Configuration);
解决方案:使用DelegatingHandler实现请求头传递
步骤1:定义自定义DelegatingHandler
创建一个继承自DelegatingHandler的类,用于在每个请求发送前添加指定请求头:
public class RequestHeaderHandler : DelegatingHandler { private readonly KeyValuePair<string, string> _requestHeader; public RequestHeaderHandler(string headerName, string headerValue) { _requestHeader = new KeyValuePair<string, string>(headerName, headerValue); } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // 避免重复添加请求头 if (!request.Headers.Contains(_requestHeader.Key)) { request.Headers.Add(_requestHeader.Key, _requestHeader.Value); } return await base.SendAsync(request, cancellationToken); } }
步骤2:修改扩展方法,支持传入请求头并注册Handler
更新AddAdminInternalServices方法,添加可选参数接收请求头信息,并通过AddHttpMessageHandler注册自定义Handler:
public static class InternalAdminServiceRegister { public const string DefaultConfigSectionName = "InternalApisOptions:Admin"; public static IServiceCollection AddAdminInternalServices( this IServiceCollection services, IConfiguration configuration, string configSectionName = DefaultConfigSectionName, (string Name, string Value)? defaultRequestHeader = null) { services.Configure<AdminOptions>(configuration.GetSection(configSectionName)); var clientBuilder = services.AddHttpClient<IInternalAdminService, InternalAdminService>((sp, client) => { var options = sp.GetRequiredService<IOptions<AdminOptions>>().Value; client.BaseAddress = new Uri(options.ServiceUrl); client.Timeout = TimeSpan.FromMilliseconds(options.TimeoutMs); }).AddPolicyHandler(GetCircuitBreakerPolicy()); // 如果传入了请求头,注册自定义Handler if (defaultRequestHeader.HasValue) { var header = defaultRequestHeader.Value; clientBuilder.AddHttpMessageHandler(() => new RequestHeaderHandler(header.Name, header.Value)); } return services; } private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy() => HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync(handledEventsAllowedBeforeBreaking: 5, durationOfBreak: TimeSpan.FromSeconds(7)); }
步骤3:在Program.cs中传递请求头
调用扩展方法时,传入需要添加的请求头键值对:
var builder = MtsHost.CreateWebApplication(args); // 传递请求头:键为"endpointService",值为"true" builder.Services.AddAdminInternalServices(builder.Configuration, defaultRequestHeader: ("endpointService", "true"));
方案优势
- 相比直接修改
DefaultRequestHeaders,DelegatingHandler是在每个请求发送前动态添加请求头,避免了HttpClient复用场景下的全局配置冲突问题。 - 扩展性更强:后续如需添加多个请求头,只需修改Handler或扩展参数即可,无需改动HttpClient的核心配置逻辑。
内容的提问来源于stack exchange,提问作者Ehsan Akbar
相关产品推荐
相关产品推荐

