如何在.NET Core中使用HttpClient
创始人
2024-11-27 16:03:56
0次

.NET开发者都通过下面的方式发送http请求:

using (var httpClient = new HttpClient())
{
 var response = await httpClient.GetAsync(uri);
  
 //do something with response
}

这段代码理论上来说遵守了C#的最佳实践,HttpClient是IDisposable类型,所以我们通过using语法糖来使用HttpClient。微软官方的文档也提到:

As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement

可是,当我们试图运行下面的测试:

public async Task SendRequest() 
{
 Console.WriteLine("Starting reqeust");
 for(int i = 0; i<10; i++)
 {
  using(var client = new HttpClient())
  {
   var result = await client.GetAsync("http://www.baidu.com");
   Console.WriteLine(result.StatusCode);
  }
 }
 Console.WriteLine("Reqeust done");
}

此时在terminal下列出所有端口:

netstat -ap tcp | grep -i "time_wait"

如何在.NET Core中使用HttpClient

你会发现本地开启了10个端口,这说明HttpClient的工作原理其实跟我们认为的IDisposable是有区别的,如果你把HttpClient用作大规模的Http请求,实际上会创建很多个Http连接,而且这些资源并不能被立即释放。一个显而易见的改进方法是共享同一个HttpClient实例,从而达到节约socket资源的目的。

private static readonly HttpClient _client = new HttpClient();
public async Task SendRequest2() 
{
 _testOutputHelper.WriteLine("Start request");
 
 for(int i = 0; i<10; i++)
 {
  var result = await _client.GetAsync("http://www.baidu.com");
  Console.WriteLine(result.StatusCode);
 }
 _testOutputHelper.WriteLine("Request done");
}

这个方案似乎解决了问题,使用单例的HttpClient的确会减少Socket资源,但是这个方案会引发新的问题:由于这个Http连接始终保持连接状态,所以当请求地址的DNS发生更新的时候并不会应用到这个Http连接上。这个问题在微服务,高可用时代更加常见Singeton HttpClient doesn't respect DNS changes。

最终,一个叫做HttpClientFactory的开源实现用来彻底解决这个问题。微软也将HttpClientFactory集成在了.NET Core中。

在.NET Core中创建HttpClient
1.添加Nuget

Microsoft.Extensions.Http

2.在Dependency Injection容器中注册服务

services.AddHttpClient();

3. 使用构造器注入使用IhttpClientFactory

public class BasicUsage
{
 private readonly IHttpClientFactory _clientFactory;

 public BasicUsage(IHttpClientFactory clientFactory)
 {
  _clientFactory = clientFactory;
 }

 public async Task SendRequest()
 {
  var request = new HttpRequestMessage(HttpMethod.Get, 
   "http://www.baidu.com");

  var client = _clientFactory.CreateClient();
  var response = await client.SendAsync(request);
  //do something for response
 }
}

4. 使用Named HttpClient

由于我们在DI容器中注册了唯一的HttpClientFactory,意味着通过HttpClientFactory创建出来的HttpClient可能是同一个配置和参数,如果你需要不同配置的HttpClient,你可以通过“起名字的”的方式注册不同的HttpClient。

services.AddHttpClient("baidu", c =>
{
 c.BaseAddress = new Uri("https://www.baidu.com");
 c.DefaultRequestHeaders.Add("Accept", "application/json");
});

一旦注册了一个名叫“baidu"的HttpClient,你就可以通过下面的方式来建创建HttpClient:

var client = _clientFactory.CreateClient("baidu");

5.集成Polly

Polly是一个用来故障处理库,它允许开发者在Http请求中添加“重试、熔断器、超时等”策略。

先添加Nuget:

Microsoft.Extensions.Http.Polly

添加策略:

var timeout = Policy.TimeoutAsync(TimeSpan.FromSeconds(10));

services.AddHttpClient("baidu")
 .AddPolicyHandler(request => timeout)
 .AddTransientHttpErrorPolicy(p=>p.RetryAsync(3));

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...