如何基于IHttpClientFactory封装自定义类统一配置DelegatingHandler与策略?
统一配置HttpClient的处理器与Polly策略方案
不需要自行实现IHttpClientFactory,原生框架已经提供了更简洁的方式封装公共配置,同时也可以通过自定义调用类简化业务层使用,以下是两种可行方案:
方案一:封装扩展方法统一配置公共逻辑
创建IServiceCollection的扩展方法,把重复的Handler注册、Polly策略配置封装进去,后续添加HttpClient时直接调用该方法,仅需传入BaseAddress这类个性化配置即可。
扩展方法代码
public static class HttpClientServiceExtensions { public static IHttpClientBuilder AddStandardHttpClient(this IServiceCollection services, string name, Action<HttpClient> configureClient) { return services.AddHttpClient(name, configureClient) .AddHttpMessageHandler<ErrorLoggingHandler>() .AddHttpMessageHandler<JwtHandler>() .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(3, retryCount => TimeSpan.FromMilliseconds(retryCount * 1000))); } }
使用方式(Program.cs/Startup.cs)
// 配置第一个HttpClient services.AddStandardHttpClient("test", httpClient => { httpClient.BaseAddress = new Uri(Configuration["url"]!); }); // 配置其他HttpClient时直接复用扩展方法 services.AddStandardHttpClient("businessClient", httpClient => { httpClient.BaseAddress = new Uri(Configuration["businessUrl"]!); });
方案二:封装自定义调用类MyHttpCaller
如果希望业务层直接调用封装好的HTTP客户端,无需关心IHttpClientFactory细节,可以创建MyHttpCaller类,内部依赖IHttpClientFactory获取配置好的HttpClient,同时封装通用调用逻辑。
1. 定义MyHttpCaller类
public class MyHttpCaller { private readonly HttpClient _httpClient; // 构造函数注入工厂,默认使用指定名称的HttpClient public MyHttpCaller(IHttpClientFactory clientFactory, string clientName = "test") { _httpClient = clientFactory.CreateClient(clientName); } // 封装Get请求逻辑 public async Task<T?> GetAsync<T>(string requestUri) { var response = await _httpClient.GetFromJsonAsync<T>(requestUri); // 可在此统一处理响应校验、异常转换等逻辑 return response; } // 按需封装Post/Put/Delete等其他HTTP方法 public async Task<TResponse?> PostAsync<TRequest, TResponse>(string requestUri, TRequest requestData) { var response = await _httpClient.PostAsJsonAsync(requestUri, requestData); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync<TResponse>(); } }
2. 注册到依赖注入容器
// 先注册标准配置的HttpClient services.AddStandardHttpClient("test", httpClient => { httpClient.BaseAddress = new Uri(Configuration["url"]!); }); // 注册MyHttpCaller,指定默认使用的客户端名称 services.AddTransient<MyHttpCaller>(sp => new MyHttpCaller(sp.GetRequiredService<IHttpClientFactory>(), "test"));
3. 在业务类中使用
public class HttpClientLib { private readonly MyHttpCaller _httpCaller; public HttpClientLib(MyHttpCaller httpCaller) { _httpCaller = httpCaller; } // 业务方法直接调用封装好的HTTP方法 public async Task<MyData> FetchBusinessDataAsync() { var data = await _httpCaller.GetAsync<MyData>("/api/business/data"); return data ?? throw new InvalidOperationException("获取数据失败"); } }
关键提醒:不要自行实现IHttpClientFactory
原生IHttpClientFactory已经处理了HttpClient的生命周期管理(避免Socket资源耗尽)、连接池复用等复杂逻辑,自行实现不仅重复造轮子,还容易引入性能或稳定性问题,完全没必要。
内容的提问来源于stack exchange,提问作者शेखर
相关产品推荐
相关产品推荐

