IHttpClientFactory笔记
在开发的过程中,遇到过这种带Factory的对象。先不扯什么工厂类,我也不知道跟工厂类有没有关联,还没有百度。
当需要向某特定URL地址发送HTTP请求并得到相应响应时,通常会用到HttpClient类。
该类包含了众多有用的方法,可以满足绝大多数的需求。但是如果对其使用不当时,可能会出现意想不到的事情。
using(var client = new HttpClient())
//下面这个讲解,使用HttpClient会使链接依然存在【TIME_WAIT】,
继续等待看是否还有延迟的包会传输过来;默认在 windows 下,TIME_WAIT 状态将会使系统将会保持该连接 240s。
在高并发的情况下,连接来不及释放,socket 被耗尽,耗尽之后就会出现喜闻乐见的一个 SocketException 错误。
(8条消息) 你可能一直在以错误的方式使用HttpClient_控制台程序 无法使用 ihttpclientfactory 程序异常退出 也没报错_菜鸟厚非的博客-CSDN博客
对象所占用资源应该确保及时被释放掉,但是,对于网络连接而言,这是错误的。
原因有二,
1:网络连接是需要耗费一定时间的,频繁开启与关闭连接,性能会受影响;
2:开启网络连接时会占用底层socket资源,但在HttpClient调用其本身的Dispose(处理/处置/安排)方法时,并不能立刻释放该资源,这意味着你的程序可能会因为耗尽连接资源而产生预期之外的异常。
所以比较好的解决方法是延长HttpClient对象的使用寿命,比如对其建一个静态的对象:
private static HttpClient Client = new HttpClient();
但从程序员的角度来看,这样的代码或许不够优雅。
所以在.NET Core 2.1中引入了新的HttpClientFactory类。
它的用法很简单,首先是对其进行IoC的注册:
1 public void ConfigureServices(IServiceCollection services) 2 { 3 services.AddHttpClient(); 4 services.AddMvc(); 5 }
然后通过IHttpClientFactory创建一个HttpClient对象,之后的操作如旧,但不需要担心其内部资源的释放:
public class LzzDemoController : Controller { IHttpClientFactory _httpClientFactory; public LzzDemoController(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public IActionResult Index() { var client = _httpClientFactory.CreateClient(); var result = client.GetStringAsync("http://myurl/"); return View(); } }
二、现有HttpClient使用方式
在.Net Core2.1后,微软引入了HttpClientFactory彻底解决这个问题,工厂模式的职责是负责创建对象,这个类主要负责创建HttpClient实例
首先在StartUp中注册,可能会提示安装这个Nuget包
services.AddHttpClient();
该方法内部实现过程可以浏览:https://www.cnblogs.com/lizhizhang/p/9502862.html
其次,在需要使用时,使用构造函数注入即可
[Route("api/[controller]")] [ApiController] public class HttpClientController : ControllerBase { IHttpClientFactory _httpClientFactory; public HttpClientController(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } [HttpGet] [Route(nameof(Index))] public async Task<IActionResult> Index() { var client = _httpClientFactory.CreateClient(); var result = await client.GetAsync("http://aspnetcore.online/api/resource/getresource"); return Ok(result); } }
具体实现原理简述为:
HttpClientFactory内部管理着一个连接句柄池,对每一个HttpClient使用一个句柄进行跟踪管理,
当该实例使用完毕后,句柄仍然控制资源释放,在短期大量处理时,可以将这部分句柄完成对不同实例的跟踪管理,
使得句柄,也就是相应的套接字生命周期延长,对套接字完成了复用。
句柄有多种意义: 1、在程序设计中,指一种特殊的智能指针 ; 2、在Windows编程中,是Windows用来标识被应用程序所建立或使用的对象的唯一整数,Windows使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。” 句柄的英文是 handle。在英文中,有操作、处理、控制之类的意义。作为一个名词时,是指某个中间媒介,通过这个中间媒介可控制、操作某样东西。
这样说有点抽象,举个例子。door handle 是指门把手,通过门把手可以去控制门,但 door handle 并非 door 本身,只是一个中间媒介。
又比如 knife handle 是刀柄,通过刀柄可以使用刀。跟 door handle 类似,我们可以用 file handle 去操作 file, 但 file handle 并非 file 本身。
这个 file handle 就被翻译成文件句柄,同理还有各种资源句柄。 句柄就是个数字,一般和当前系统下的整数的位数一样,比如32bit系统下就是4个字节。这个数字是一个对象的唯一标示,和对象一一对应。
这个对象可以是一个块内存,一个资源,或者一个服务的context(如 socket,thread)等等。
这个数字的来源可以有很多中,只要能保证和它代表的对象保持唯一对应就可以,比如可以用内存地址,也可以用句柄表的序号,或者干脆用一个自增ID,再或者用以上的值去异或一个常数。