.NetCore 2.1中的HttpClientFactory最佳实践

原文:.NetCore 2.1中的HttpClientFactory最佳实践

.NET Core 2.1中的HttpClientFactory最佳实践

ASP.NET Core 2.1中出现一个新的HttpClientFactory功能,

它有助于解决开发人员在使用HttpClient实例从其应用程序发出外部Web请求时可能遇到的一些常见问题。

介绍

在.NETCore平台的2.1新增了HttpClientFactory,虽然HttpClient这个类实现了disposable,但使用它的时候用声明using包装块的方式通常不是最好的选择。处理HttpClient,底层socket套接字不会立即释放。该HttpClient类是专为多个请求重复使用而创建的。需要不同的基地址,不同的HTTP标头和其他对请求个性化操作的场景时,需要手动管理多个HttpClient实例,为了简化HttpClient实例管理,.NET Core 2.1提供了一个新的HTTPClientFactory - 它可以创建,缓存和处理HttpClient实例。

什么是HttpClientFactory?

用ASP.NET团队的话说:“an opinionated factory for creating HttpClient instances”(一个用于创建HttpClient实例的最佳实践的工厂),并且是ASP.NET Core 2.1发布的新功能。根据大家以前使用HttpClient的经验,您可能遇到一些困扰的问题,有时甚至没有意识到您有问题(只是在并发并不大的场景没触发而已)。

第一个问题是当你在代码中创建太多的HttpClients时,这反过来会产生两个问题......

  1. 这是低效的,因为每个请求都有自己的远程服务器连接池。这意味着您需要为每个创建的客户端支付重新连接到该远程服务器的成本。
  2. 更大的问题是如果你创建了很多HttpClient并使用到他们,你可以遇到Socket耗尽,而你基本上已经太快地使用了过多的Socket。您可以同时打开多个Socket是有限制的。当您dispose销毁HttpClient时,它打开的连接在TIME_WAIT状态下保持打开状态最长240秒(如果来自远程服务器的任何数据包仍然通过)。

HttpClient实现了IDisposable,这通常会导致开发人员在使用IDisposable对象时遵循正常模式,在using块中创建它。这样可以确保一旦完成对象并且它已经超出范围,就可以正确销毁对象。

因此,最优的方法是重用HttpClient实例,以便也可以重用连接。HttpClient是一个可变对象,但只要你没有运行期改变它,它实际上是线程安全的并且可以共享。因此,一种常见的方法是将其注册为具有DI框架的单例模式,或者创建包含static静态实例的对象。

但是,这会产生新问题。以这种方式使用单个HttpClient将保持连接打开并且不遵守DNS生存时间(TTL)设置(总之就是同一个HttpClient实例只能有一个请求头,在被请求方发生更改时,由于是单例不能做个性化改变,否则导致其他请求失败)。现在连接将永远不会获得DNS更新,因此您正在与之通信的服务器将永远不会更新其地址。在某些情况下,这是完全有可能的,在以上这种情况下,您可以平衡许多主机,这些主机可能随着时间的推移而改变,或者可能使用Blue/Green 部署推出新服务。如果服务器消改变,则您的连接使用的IP可能不再响应您通过单个HttpClient发出的请求。

所以需要我们手动去管理每类服务器的HttpClient的实例来进行个性化请求头的构造和发起请求!

HttpClientFactory旨在帮助您开始解决这些问题,并提供了一种新的机制来创建在幕后为我们正确管理的HttpClient实例。它将为我们“做管理HttpClient的事”,我们可以专注于业务!虽然在参考HttpClient时提到了上述问题,但事实上问题的根源实际上发生在HttpClient上,HttpClient使用了HttpClientHandler。HttpClientFactory管理处理程序的生命周期,以便我们有一个可以重用的池,同时还可以(Rotating)轮换它们以使DNS不会过时。

使用HttpClient的昂贵部分实际上是创建HttpClientHandler和连接。以这种HttpClientFacotry方式汇集这些内容意味着我们可以更高效利用资源最节省地使用我们系统上的socket。当您使用HttpClientFactory请求HttpClient时,实际上每次都会获得一个新实例,这意味着我们不必担心会改变它的状态。此HttpClient可能(或可能不)使用池中的现有HttpClientHandler,从而使用现有打开的连接。

默认情况下,每个新创建的HttpClientHandler(派生自HttpMessageHandler)生命周期只有2分钟。通过services.AddHttpClient()创建HttpClientFactory实例时,可以根据每一个命名的Client客户机进行控制。达到生命周期后,处理程序将不会立即被释放掉,而是放入过期的池中。任何依赖于HttpClientFactory的处理程序链的客户端都可以继续使用它而没有任何问题。有一个后台作业检查过期的池,以查看处理程序的所有引用是否已在scope之外,此时可以将其释放掉。处理程序链过期后对新客户端的任何新请求都将获得新的处理程序链。

这种方法运行得相当不错,但.NET Core方面还有其他一些事情可能会进一步改善这种情况。.NET Core团队开发了一个新的ManagedHandler,它可以更正确地管理DNS,原则上可以保持更长时间,这意味着可以更有效地共享连接。这个新的处理程序还被设计为在不同的操作系统中更加一致地运行。在该工作完成之前,上面的处理程序池是一个合理的解决方法。

如何使用HttpClientFactory

我们将首先创建一个简单的WebAPI项目

接下来,我们需要转到我们的Startup.cs文件并注册一个服务。

services.AddHttpClient();

services.AddScoped(typeof(ClassInService));//此处无关HttpClient,请暂时忽视他

在幕后,这将注册一些必需的服务,其中一个是IHttpClientFactory的实现。接下来,我们在业务中使用他

  public class ClassInService
    {
        /// <summary>
        /// 构建器
        /// </summary>
        /// <param name="clientFactory"></param>
        public ClassInService(IHttpClientFactory clientFactory)
        {
            _clientFactory = clientFactory;
        }
}
private void HttpClientFactoryTest()
        {
            var client = _clientFactory.CreateClient("这是专门用来连接博客园的");//必须和services.AddHttpClient()中指定的名称对应
            var content = new StringContent($"SID={SID}&safeKey={111}");
            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

            var response = client.PostAsync("MyBlogUrl", content);
        }

这里我们首先添加对IHttpClientFactory的依赖,它将由DI系统注入ClassInService。IHttpClientFactory允许我们请求和接收HttpClient实例。

我们使用HttpClientFactory创建客户端。在幕后,HttpClientFactory将为我们创建一个新的HttpClient。但是等等,之前说过为每个请求使用新的HttpClient是很糟糕。但此处的创建的httpclient是在他所管理的池子中,并不每个请求都会是新的socket。

HttpClientFactory收集这些HttpClientHandler实例并管理它们的生命周期,以解决之前提到的一些问题。每次我们要求HttpClient时,我们都会得到一个新实例,它可能(或可能不)使用现有的HttpClientHandler。HttpClient本身并没有问题。

一旦创建,由此创建的所有HttpClientHandler将被默认保持约2分钟。这意味着针对同一个CreateClient的任何新请求都可以共享处理程序,因此也可以共享连接。当HttpClient存在时,它的处理程序将保持可用状态,并且它将再次共享连接。

两分钟后,每个HttpClientHandler都标记为已过期。过期状态只是标记它们,以便在创建任何新的HttpClient实例时不再使用它们。但是,它们不会立即销毁,因为其他HttpClient实例可能正在使用它们。HttpClientFactory使用后台服务监视过期的处理程序,一旦它们不再被引用,就可以正确释放它们,也允许它们的连接被关闭。

概要

通过使用HttpClientfactory我们不需要考虑如何管理HttpClient的生命周期或担心遇到DNS问题。以上只是HttpClient小小的最佳使用推荐,还有其他高级用法,例如和Polly的结合使用。

参考:https://www.stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore

原文地址:https://www.cnblogs.com/lonelyxmas/p/10223143.html

时间: 2024-11-08 23:20:22

.NetCore 2.1中的HttpClientFactory最佳实践的相关文章

.NET Core 2.1中的HttpClientFactory最佳实践

ASP.NET Core 2.1中出现一个新的HttpClientFactory功能, 它有助于解决开发人员在使用HttpClient实例从其应用程序发出外部Web请求时可能遇到的一些常见问题. 介绍 在.NETCore平台的2.1新增了HttpClientFactory,虽然HttpClient这个类实现了disposable,但使用它的时候用声明using包装块的方式通常不是最好的选择.处理HttpClient,底层socket套接字不会立即释放.该HttpClient类是专为多个请求重复使

XAML: 自定义控件中事件处理的最佳实践

在开发 XAML(WPF/UWP) 应用程序中,有时候,我们需要创建自定义控件 (Custom Control) 来满足实际需求.而在自定义控件中,我们一般会用到一些原生的控件(如 Button.TextBox 等)来辅助以完成自定义控件的功能. 自定义控件并不像用户控件 (User Control) 一样,使用 Code-Behind(UI 与逻辑在一起)技术.相反,它通过把 UI 与逻辑分离而将两者解耦.因此,创建一个自定义控件会产生两个文件,一个是 Generic.xaml,在它里面定义其

Window下使用Xshell连接VirtualBox中CentOS SSH最佳实践

网上已经有非常多讲怎样连接VMware的文章.可是针对一些可能遇到的细节没有讲全. 这里会有一个非常 实际的样例,附带全部软件的链接,保证成功. 最佳实践什么的都是骗人的. 1.安装VirtualBox 其实VMware会有更全面的虚拟化支持,比方cuda,这里选择VirtualBox更easy上手一些,对一个开发环境来说够用. VirtualBox直接去官网下载最新版,然后记得下载VirtualBox Extension Pack.当前版本号的VirtualBox相应的VirtualBox E

.NET中异常处理的最佳实践(转)

原文地址:http://www.cnblogs.com/xiaozhi_5638/p/4259115.html 目录 介绍 做最坏的打算 提前检查 不要信任外部数据 可信任的设备:摄像头.鼠标以及键盘 “写操作”同样可能失效 安全编程 不要抛出“new Exception()” 不要将重要的异常信息存储在Message属性中 每个线程要包含一个try/catch块 捕获异常后要记录下来 不要只记录Exception.Message的值,还需要记录Exception.ToString() 要捕获具

.NET中异常处理的最佳实践(译)

本文翻译自CodeProject上的一篇文章,原文地址. 目录 介绍 做最坏的打算 提前检查 不要信任外部数据 可信任的设备:摄像头.鼠标以及键盘 "写操作"同样可能失效 安全编程 不要抛出"new Exception()" 不要将重要的异常信息存储在Message属性中 每个线程要包含一个try/catch块 捕获异常后要记录下来 不要只记录Exception.Message的值,还需要记录Exception.ToString() 要捕获具体的异常 不要中止异常上

【转】Java中关于异常处理的十个最佳实践

原文地址:http://www.searchsoa.com.cn/showcontent_71960.htm 导读:异常处理是书写强健Java应用的一个重要部分,Java许你创建新的异常,并通过使用 throw 和 throws关键字抛出它们. 异常处理是书写强健Java应用的一个重要部分,它是关乎每个应用的一个非功能性需求,是为了优雅的处理任何错误状况,比如资源不可访问,非法输入,空输入等等.Java提供了几个异常处理特性,以try,catch和 finally 关键字的形式内建于语言自身之中

Java 编程中关于异常处理的 10 个最佳实践

异常处理是书写 强健 Java应用的一个重要部分.它是关乎每个应用的一个非功能性需求,是为了优雅的处理任何错误状况,比如资源不可访问,非法输入,空输入等等.Java提供了几个异常处理特性,以try,catch和finally 关键字的形式内建于语言自身之中.Java编程语言也允许你创建新的异常,并通过使用  throw 和 throws关键字抛出它们.事实上,异常处理不仅仅是知道语法.书写一个强健的代码更多的是一门艺术而不仅仅是一门科学,这里我们将讨论一些关于异常处理的Java最佳实践.这些 J

编程中关于异常处理的10个最佳实践

在实践中,异常处理不单单是知道语法这么简单.编写健壮的代码是更像是一门艺术,在本文中,将讨论java异常处理最佳实践.这些Java最佳实践遵循标准的JDK库,和几个处理错误和异常的开源代码.这还是一个提供java程序员编写健壮代码的便利手册. Java 编程中异常处理的最佳实践 这里是我通过在国内著名的IT培训平台扣丁学堂在线学习收集的10个java编程中进行异常处理的10最佳实践.在Java编程中对于检查异常有褒有贬,强制处理异常是一门语言的功能.在本文中,我们将尽量减少使用检查型异常,同时学

《.NET最佳实践》与Ext JS/Touch的团队开发

概述 有不少开发人员都问过我,Ext JS/Touch是否支持团队开发?对于这个问题,我可以毫不犹豫的回答:支持.原因是在Sencha官网博客中客户示例中,有不少项目都是基于团队模式开发的. 那为什么会出现这个问题?我觉得问题的关键在于不知道如何去进行模块独立调试或做最终的整合.对于这个问题,我觉得<.NET最佳实践>这本书(下 文中简称为实践一书)或许会给大家带来一点启示.虽然这本书是针对.NET而写的,但我觉得,这对于Ext JS/Touch,甚至于其他开发语言的开发,还是有不错的借鉴意义