.NET Core中HttpClient的正确打开方式
前言
在 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,请赶快试试新的方案吧。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
上一篇: 基于C#对用户密码使用MD5加密与解密
推荐阅读
-
ASP.NET Core 2.2中的Endpoint路由详解
-
ASP.NET Core中自定义路由约束的实现
-
详解.NET Core 3.0中的新变化
-
ASP.NET Core中预压缩静态文件的方法步骤
-
浅谈.net core 注入中的三种模式:Singleton、Scoped 和 Transient
-
详解ASP.Net Core 中如何借助CSRedis实现一个安全高效的分布式锁
-
浅析.Net Core中Json配置的自动更新
-
Asp.Net Core 轻松学-HttpClient的演进和避坑
-
Asp.Net Core中基于Session的身份验证的实现
-
(14)ASP.NET Core 中的日志记录