IHttpClientFactory笔记

在开发的过程中,遇到过这种带Factory的对象。先不扯什么工厂类,我也不知道跟工厂类有没有关联,还没有百度。

当需要向某特定URL地址发送HTTP请求并得到相应响应时,通常会用到HttpClient类

该类包含了众多有用的方法,可以满足绝大多数的需求。但是如果对其使用不当时,可能会出现意想不到的事情。

using(var client = new HttpClient())

为什么不用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,再或者用以上的值去异或一个常数。

 

 

 

直达原文

posted @ 2020-05-19 10:06  ProZkb  阅读(716)  评论(0编辑  收藏  举报