asp.net core 中HttpClient IHttpClientFactory http请求的正确用法
2022-06-20HttpClient 类非常易于使用,虽然此类实现 IDisposable,但在 using 语句中声明和实例化它并非首选操作,因为释放 HttpClient 对象时,基础套接字不会立即释放,这可能会导致套接字耗尽问题。 因此,HttpClient 应进行一次实例化并在应用程序的生命周期中重复使用。 在负载较重的情况下,实例化每个请求的 HttpClient 类将耗尽可用的套接字数。 该问题会导致 SocketException 错误。 要解决此问题,可能的方法是将 HttpClient 对象创建为单一对象或静态对象, 对于生存期较短的控制台应用或一天运行几次的类似应用,这可能是一个不错的解决方案。在长期运行的进程中使用 HttpClient 的共享实例时,开发人员会遇到另一个问题。 在将 HttpClient 实例化为单一实例或静态对象的情况下,它无法处理 DNS 更改,要解决上述问题并使 HttpClient 实例可管理,.NET Core 2.1 引入了 IHttpClientFactory 接口,该接口可用于在应用中通过依赖关系注入 (DI) 来配置和创建 HttpClient 实例。 它还提供基于 Polly 的中间件的扩展,以利用 HttpClient 中的委托处理程序。
使用 IHttpClientFactory 的好处
同时实现 IHttpMessageHandlerFactory 的 IHttpClientFactory 当前实现具有以下优势:
提供一个中心位置,用于命名和配置逻辑 HttpClient 对象。 例如,可以配置预配置的客户端(服务代理)以访问特定微服务。
通过后列方式整理出站中间件的概念:在 HttpClient 中委托处理程序并实现基于 Polly 的中间件以利用 Polly 的复原策略。
HttpClient 已经具有委托处理程序的概念,这些委托处理程序可以链接在一起,处理出站 HTTP 请求。 将 HTTP 客户端注册到工厂后,可使用一个 Polly 处理程序将 Polly 策略用于重试、断路器等。
管理 HttpMessageHandler 的生存期,避免在自行管理 HttpClient 生存期时出现上述问题。
IHttpClientFactory 的多种用法
可以通过多种方法在应用程序中使用 IHttpClientFactory:
1.基本用法
在启动方法中使用AddHttpClient来注册IHttpClientFactory。
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
}
在需使用的地方
public class TestController:Controller
{
private readonly IHttpClientFactory _httpClientFactory;
public TestController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public IActionResult Home()
{
var client = _clientFactory.CreateClient();
...
}
}
2.命名化 HttpClient
有时候项目中可能会用到多个client,每个client也需要不同的配置,比如做爬虫你可能要带上Cookie信息,诸如此类的需求,这时候我们就可以使用命名化HttpClient。
services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
// Github API versioning
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
// Github requires a user-agent
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
在需使用的地方
public class TestController:Controller
{
private readonly IHttpClientFactory _httpClientFactory;
public TestController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public IActionResult Home()
{
var client = _clientFactory.CreateClient("github");
...
}
}
3.类型化 HttpClient
启动类中注册
public class CatalogService : ICatalogService
{
private readonly HttpClient _httpClient;
private readonly string _remoteServiceBaseUrl;
public CatalogService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<Catalog> GetCatalogItems(int page, int take,int? brand, int? type)
{
var uri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl,page, take, brand, type);
var responseString = await _httpClient.GetStringAsync(uri);
var catalog = JsonConvert.DeserializeObject<Catalog>(responseString);
return catalog;
}
}
AddHttpClient 将 CatalogService 注册为暂时性服务。 此注册使用工厂方法执行以下操作:
创建 HttpClient 的实例。
创建 CatalogService 的实例,将 HttpClient 的实例传入其构造函数。
services.AddHttpClient<ICatalogService, CatalogService>();//普通注册
services.AddHttpClient<ICatalogService, CatalogService>(c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
}); // 配置
在需要使用的地方
public class TestService
{
private readonly ICatalogService _catalogSerice;
public TestService(ICatalogService catalogSerice)
{
_catalogSerice = catalogSerice;
}
public IActionResult Home()
{
}
}
配合Polly实现弹性策略,比如重试次数,熔断等,使用 Polly 可定义一个重试策略,其中包含重试次数、指数退避算法配置以及在出现 HTTP 异常时要采取的操作,例如记录错误。
使用Polly需要引用Microsoft.Extensions.Http.Polly包
services.AddHttpClient<ICatalogService, CatalogService>(client =>
{
client.BaseAddress = new Uri(Configuration["BaseUrl"]);
}).SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Set lifetime to five minutes
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(Policy.TimeoutAsync(10).AsAsyncPolicy<HttpResponseMessage>());
.AddPolicyHandler(GetCircuitBreakerPolicy());
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));//策略配置为尝试 6 次(采用指数重试),以 2 秒为起始值
//另外的写法
.WaitAndRetryAsync(new[]
{//请求最多 3 次。该策略将在第一次重试之前应用 1 秒的延迟;第二次重试前 5 秒;第三次前10秒。
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
}));
}
https://docs.microsoft.com/zh-cn/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
https://docs.microsoft.com/zh-cn/dotnet/architecture/microservices/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly
https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory
https://blog.csdn.net/zyq025/article/details/118014870
https://www.cnblogs.com/aoximin/p/14967945.html