当前位置: 移动技术网 > IT编程>开发语言>.net > .NET Core中HttpClient的正确打开方式

.NET Core中HttpClient的正确打开方式

2019年05月28日  | 移动技术网IT编程  | 我要评论

神医异界风流,dnf超级助手下载,平安银行 平安盈

前言

在 asp.net core 1.0 时代,由于设计上的问题, httpclient 给开发者带来了无尽的困扰,用 asp.net core
开发团队的话来说就是:我们注意到,httpclient 被很多开发人员不正确的使用。得益于 .net core
不断的版本快速升级;

问题来源

长期以来,.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"

你会发现本地开启了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<httpresponsemessage>(timespan.fromseconds(10));

services.addhttpclient("baidu")
 .addpolicyhandler(request => timeout)
 .addtransienthttperrorpolicy(p=>p.retryasync(3));

当然还有一些高阶用法,详见initiate http requests,总之httpclientfactory提供了一种高效实用httpclient的方式,如果你还在自己new httpclient,请赶快试试新的方案吧。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网