在C#中,
IHttpClientFactory是 .NET Core 2.1+ 推荐的创建和管理
HttpClient实例的方式,它解决了直接 new
HttpClient带来的连接泄漏、DNS刷新不及时、配置复用难等问题。
为什么不能直接 new HttpClient?
每次 new
HttpClient都会创建新的底层
HttpClientHandler,而后者持有连接池和 DNS 缓存。频繁创建销毁会导致: Socket 耗尽(TIME_WAIT 状态堆积) DNS 变更无法及时生效(默认缓存 2 分钟) SSL/TLS 会话无法复用,影响性能
而
IHttpClientFactory通过统一管理
HttpMessageHandler生命周期(默认 2 分钟重用,支持自定义策略),让多个
HttpClient实例共享底层资源。
注册和基础用法
在
Program.cs(.NET 6+)或
Startup.ConfigureServices中注册:
builder.Services.AddHttpClient(); // 默认命名客户端
然后在服务中注入并使用:
public class WeatherService
{
private readonly IHttpClientFactory _factory;
public WeatherService(IHttpClientFactory factory) => _factory = factory;
public async Task<string> GetWeatherAsync()
{
var client = _factory.CreateClient(); // 创建轻量级 HttpClient 实例
return await client.GetStringAsync("https://api.example.com/weather");
}
}
注意:
CreateClient()返回的是“逻辑客户端”,不是新连接——底层 handler 是复用的。
命名客户端与类型化客户端(推荐)
避免魔法字符串,用命名或类型化方式组织不同用途的客户端:
命名客户端:适合简单场景,注册时指定名称和配置builder.Services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.UserAgent.ParseAdd("MyApp/1.0");
});
使用时传入名称:
var client = _factory.CreateClient("github");
类型化客户端(Type-Safe Client):更推荐,把 HTTP 调用封装成强类型服务
public class GitHubService
{
private readonly HttpClient _client;
public GitHubService(HttpClient client)
{
_client = client;
_client.BaseAddress = new Uri("https://api.github.com/");
_client.DefaultRequestHeaders.UserAgent.ParseAdd("MyApp/1.0");
}
public async Task<IEnumerable<Repo>> GetReposAsync(string user) =>
await _client.GetFromJsonAsync<IEnumerable<Repo>>($"/users/{user}/repos");
}
// 注册
builder.Services.AddHttpClient<GitHubService>();
使用时直接注入
GitHubService,无需手动创建 client,也天然支持依赖注入和测试模拟。
添加拦截、重试、熔断等策略
通过
AddPolicyHandler、
AddTransientFaultHandler等扩展方法集成
Polly:
builder.Services.AddHttpClient<GitHubService>()
.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(500)))
.AddTypedClient<GitHubService>();
常见组合:
重试策略:对 5xx、网络异常自动重试 熔断器(Circuit Breaker):连续失败后快速失败,避免雪崩 超时策略:为每个请求单独设置超时(比HttpClient.Timeout更灵活)
注意:策略作用于 handler 级别,不是 client 级别;同一命名客户端的所有请求都会应用相同策略。
基本上就这些。用好
IHttpClientFactory的关键是——别自己 new
HttpClient,优先选类型化客户端 + Polly 策略,再配合命名隔离不同服务域。不复杂但容易忽略细节。
