HttpClientFactory in ASP.NET Core 2.1 Part 1

原文地址:https://www.stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore

在 ASP.NET Core 2.1 中带来了一个新的 HttpClientFacotory 特性,在从应用使用 HttpClient 实例对外发出 Web 请求的时候,它可以帮助开发者解决常见的问题。

介绍

本文完成于 2017 年 10 月中旬,当时我注意到新的 HttpClientFactory 出现在 GitHub 的仓库中,我对它的出现很好奇,并好奇 ASP.NET 团队接下来要做什么,所以我深入到此时的代码中。从此时开始我一直关注着它,通过阅读提交的内容、问题和改进请求讨论来观察功能的演进。

最近,该特性开始被讨论的越来越多,在最近的 Damian Edwards 和 David Fowler 在 NDC 伦敦的讨论中也被涉及。实际上,在撰写本介绍的时候,它还被展示在 Jeff Fritz’s livestream showASP.NET Community Standup。Ryan Nowak 的建议是,他是 ASP.NET 主力团队中该功能的开发者之一,是现在已经足够稳定可以基于它开发开发了。

注:请注意到本文是在官方预览发布之前撰写的,进而,在正式发布的时候,情况可能发生了一些变化,

什么是 HttpClientFactory?

在 ASP.NET 团队的词汇里,它是 用来创建 HttpClient 实例的工厂,并且是伴随 ASP.NET Core 2.1 发布带来的新特性。基于你过去使用 HttpClient 的体验,你可能遇到也可能没有遇到一些问题,有时甚至你没有感到是问题。

第一个问题是,当你在应用中创建多个 HttpClient 实例的时候,你会遇到两个问题:

  1. 它是低效的,因为每个都会针对远程服务器拥有自己的连接池。这意味着你会在每个客户端每次重新连接到远程服务器的时候花费代价。
  2. 更大的问题是,如果你创建了大量的 HttpClient,你会遇到 socket 耗尽问题,你太快地使用了大量 socket。你同时可以打开多少 socket 存在一个限额。当你 dispose HttpClient 的时候,它会保持已经打开的连接直到 240s 在 TIME_WAIT 状态 (此时,来自远程服务器的包仍然可以到达)。

HttpClient 实现了 IDispose 接口,这通常导致开发者遵循通常的在使用 IDisposable 对象,使用 using 块来创建它。这可以确保在一旦你完成操作,对象的生命周期离开 scope 的时候被 dispose 掉。如果你希望更深入了解这一点,更好的文档是来自 ASP.NET 怪兽的 “You’re using HttpClient wrong and it’s destablizing your software”

推荐的使用方式是重用 HttpClient 实例,以便它的连接可以被重用。HttpClient 可以被重复使用,且不会导致问题。它是线程安全且可以共享的。常见的方式是将它注册为一个 DI 框架中的单例,或者创建一个封装器将它作为静态成员持有。

但是,这导致了另一个问题。使用单个的 HttpClient 将保持连接打开以至于不会实时刷新 DNS。现在该连接将永远不会获得 DNS 更新,所以你永远不会得到你要访问的服务器地址的最新更新。你在多个服务器之间做负载均衡的时候,或者做蓝/绿部署的时候就是一个大问题。如果服务器已经下线了,那么你使用 HttpClient 连接的 IP 也将不会对请求做出响应。关于此问题,可以阅读 “Singleton HttpClient? Beware of this serious behaviour and how to fix it” and “Singleton HttpClient doesn’t respect DNS changes”.

HttpClientFacotory 是用来帮助解决这些问题,并提供了一个新的机制来创建 HttpClient 实例,可以在后台为我们很好地管理它们。它可以为我们做正确的事,我们可以专注于其它的问题,而不是上述列举的直接使用 HttpClient 带来的问题。HttpClientFactory 管理处理器的生命周期,所以我们拥有了一个可以重用的连接池,它还会进行轮换,所以 DNS 也不会固定掉。

使用 HttpClient 的代价本质上是创建 HttpClientHandler 和连接。池化意味着我们可以更有效地使用连接。当你通过 HttpClientFactory 来获取 HttpClient 的时候,每次都会得到一个新的 HttpClient 对象,这意味着你不必担心状态变化的问题。HttpClient 可能 (也可能没有) 使用现存在的池中的 HttpClientHandler ,进而使用现存的已经打开的连接。

默认情况下,每个新的 HttpClientHandler (从 HttpMessageHander 派生) 将会被创建为一个 2 分钟生命周期。在创建它的处理器链的时候,可以针对名称控制。一旦到达生命周期,它不是马上被 disposed,而是被放入到一个过期池中。任何还在使用它的客户端可以继续使用它而不会有问题。有一个后台线程负责检查过期池,检查是否所有针对 handler 的引用已经无效了,此时它可以被真正 dispose 掉。一旦处理器过期,任何新的对客户端的请求都将返回新的处理器。

该机制可以工作很好,但是还有其他的 .NET Core 方面的情况,可能在未来改进。.NET Core 团队致力于新的 MessageHandler ,它可以更正确地管理 DNS,它的任务更为长久,意味着连接可以更为有效地共享。新的处理器还被设计为跨操作系统的更加一致的功能,到该工作完成时,上面的池化处理器只是一个临时处理。

如何使用 HttpClientFactory

本文中,我将演示最为基本的使用场景之一来开始使用 HttpClientFactory。为了该示例,我们将缠绵一个简单的 WebAPI 项目,然后编辑 .csproj 文件来升级到新的 ASP.NET Core 2.1 版本。

然后,我们需要打开 Startup.cs 文件,并注册一个服务。HttpClientFactory 包含有多种注册的变体,我们使用的方式如下所示:

service.AddHttpClient();

在幕后,这将注册一些必要的服务,其中实现了接口 IHttpClientFactory。随后,我们需要更新默认的控制器来使用该特性。

在控制器中,我们将添加针对 IHttpClientFactory 的依赖,它将通过依赖注入注入到控制器中。IHttpClientFactory 支持我们请求并接收 HttpClient 实例。

在 Get action 操作方法中,使用 HttpClientFactory 来创建客户端。在幕后,HttpClientFactory 将创建一个新的 HttpClient 实例。但是请稍等,不是使用前面的 new 操作符来针对每次请求创建,相反,有点不同的是,HttpClient 不是真正的问题,是 HttpClientHandler 用来发出 Http 调用,它才是真正的问题。它打开到外部服务的连接,然后保持打开并阻塞 socket,甚至在 HttpClient 被 dispose 之后。

HttpClientFactory 池化 HttpClientHandler 实例并管理其生命周期,以解决我前面介绍的问题。每次在请求一个 HttpClient 实例的时候,我们得到一个新的实例,它可能也可能不是使用现存的 HttpClientHandler。而 HttpClient 本身并不难构建,所以构建新的 HttpClient 并不是问题。

一旦创建的 HttpClientHandler 被池化,默认被持有 2 分钟。这意味着新的请求创建 HttpClient 可能共享底层的处理器,进而共享连接。在 HttpClient 活动的时候,它使用的底层处理器保持可用并继续共享连接。

在 2 分钟之后,每个 HttpClientHandler 被标记为过期。标记为过期状态只是简单地标记,所以只是在任何新的创建 HttpClient 实例的时候不再被使用。并不是立即被 dispose 掉。实际上,其它的 HttpClient 可能还在使用它。HttpClientFactory 使用后台服务来监控这些过期的处理器,一旦它们不再被引用,就会正确地 dispose 掉,使得底层的连接也被关闭掉。

池化功能帮助减少了 socket 耗尽的风险,刷新过程则通过确保没有长寿命的 HttpClientHandler 实例来帮助解决 DNS 更新问题,以及连接挂起问题。通过 HttpClientFactory 功能来管理是一个合理的折衷方案,

总结

这只是一个介绍文章,后面的文章将深入 HttpClientFactory 的高级特性,如何基于配置创建命名的 HttpClient ,如何创建类型化的 HttpClient,这才是真正的闪光点。希望你能够掌握它们,即是在基本的示例中。如何改进对 HttpClient 的使用,更加有效和正确。我们不需要考虑管理客户端的生命周期,或者担心掉入 DNS 问题。

Part 1 – HttpClientFactory in ASP.NET Core 2.1 Part 1 介绍

Part 2 – HttpClientFactory in ASP.NET Core 2.1 Part 2:定义命名和类型化的客户端

Part 3 – HttpClientFactory in ASP.NET Core 2.1 Part 3: 对处理器使用对外请求中间件

Part 4 – HttpClientFacotry Part 4: 集成 Polly 处理瞬时失效

Part 5 – HttpClientFactory in ASP.NET Core 2.1 Part 5: 日志

HttpClientFactory in ASP.NET Core 2.1 Part 1 介绍的更多相关文章

  1. ASP.NET Core 中的 Razor 页面介绍

    标题:ASP.NET Core 中的 Razor 页面介绍 地址:https://docs.microsoft.com/zh-cn/aspnet/core/razor-pages/index?view ...

  2. ASP.NET Core 应用程序Startup类介绍

    Startup类配置服务和应用程序的请求管道. Startup 类 ASP.NET Core应用程序需要一个启动类,按照惯例命名为Startup.在主程序的Web Host生成器(WebHostBui ...

  3. asp.net core系列 53 IdentityServer4 (IS4)介绍

    一.概述 在物理层之间相互通信必须保护资源,需要实现身份验证和授权,通常针对同一个用户存储.对于资源安全设计包括二个部分,一个是认证,一个是API访问. 1 认证 认证是指:应用程序需要知道当前用户的 ...

  4. ASP.NET Core 应用程序Startup类介绍 (转载)

    Startup类配置服务和应用程序的请求管道. Startup 类 ASP.NET Core应用程序需要一个启动类,按照惯例命名为Startup.在主程序的Web Host生成器(WebHostBui ...

  5. asp.net core系列 72 Exceptionless使用介绍

    一.Exceptionless介绍 Exceptionless专注于.net平台提供实时错误和日志报告.主要包括:错误通知.智能分组异常.详细错误报告堆栈跟踪.支持离线.UI查看重要错误和确定优先级. ...

  6. ASP.NET Core 中的 依赖注入介绍

    ASP.NET Core 依赖注入 HomeController public class HomeController : Controller { private IStudentReposito ...

  7. ASP.NET Core身份认证服务框架IdentityServer4 介绍

    IdentityServer4是ASP.NET Core 2的OpenID Connect和OAuth 2.0框架.它可以在您的应用程序中提供以下功能: 它使你的应用程序具有如下特点: 认证即服务 适 ...

  8. 菜鸟入门【ASP.NET Core】9:RoutingMiddleware介绍以及MVC引入

    前言 前面介绍了使用app.Map来配置路由,但是对于一般不是特别大的项目来说,不使用Map来进行路由配置. 配置路由 我们首先需要在Startup.cs文件中的ConfigureServices方法 ...

  9. asp.net core系列 65 正反案例介绍SOLID原则

    一.概述 SOLID五大原则使我们能够管理解决大多数软件设计问题.由Robert C. Martin在20世纪90年代编写了这些原则.这些原则为我们提供了从紧耦合的代码和少量封装转变为适当松耦合和封装 ...

  10. asp.net core网关Ocelot的简单介绍& Ocelot集成Identity认证

    文章简介  Ocelot网关简介 Ocelot集成Idnetity认证处理 Ocelot网关简介 Ocelot是一个基于netcore实现的API网关,本质是一组按特定顺序排列的中间件.Ocelot内 ...

随机推荐

  1. 数组 Array 的属性 和 方法总结

    1. Array 的属性 2. Array 的方法 2.1 增加数组单元 参数一半都是数组单元 a)unshift 方法 在数组的最前面添加数组元素 <script> const arr ...

  2. python实现链表(单链,双链)

    # code:utf-8 # createTime:2023.8.17 # -------------------------------------------------------------- ...

  3. OpenFunction v1.1.0 发布:新增 v1beta2 API,支持 Dapr 状态管理

    OpenFunction 是一个开源的云原生 FaaS(Function as a Service,函数即服务)平台,旨在帮助开发者专注于业务逻辑的研发.在过去的几个月里,OpenFunction 社 ...

  4. EAFP 与 LBYL 风格

    EAFP 与 LBYL 是两种"防御性处理机制",相信你一定接触过,只是可能没有深入思考过这个问题. 输入两个数,要输出相除后的结果: a, b = map(int, input( ...

  5. OpenGL with GLFW GLAD and CMAKE

    0. 前言 首先,无论是在youtube还是网站上,许多OpenGL的环境配置都是在VS studio里配置的,个人比较喜欢使用VS code,以及Cmake. 下文给出了一个Cmake版本关于 GL ...

  6. AMCL 原理解读

    AMCL(adaptive Monte Carlo Localization)自适应蒙特卡洛定位,A也可以理解为augmented,,源于MCL算法的一种增强,是机器人在二维移动过程中概率定位系统,采 ...

  7. LeetCode题目练习记录 _栈、队列01 _20211012

    LeetCode题目练习记录 _栈.队列01 _20211012 84. 柱状图中最大的矩形 难度困难1581 给定 n 个非负整数,用来表示柱状图中各个柱子的高度.每个柱子彼此相邻,且宽度为 1 . ...

  8. Java基础完结

    花费了大概一周的时间,看完了韩顺平的Java基础课,不得不说韩老师讲的java基础还是相当仔细的,细节满满,我认为这既是优点也是缺点吧23333333-- 接下来准备看老杜的MySQL,因为没有配套的 ...

  9. Windows Server 开启远程桌面

    工作中不可避免地经常要用到WindowsServer,为了使用的方便,配置了远程桌面,这里记录一下远程桌面配置过程中遇到的一些问题以及解决方法. Windows Server2008 R2 x64 1 ...

  10. python3的json数据库-TinyDB初入门

    无意间看到TinyDB这个词汇,就去查了一下,就发现了它的官方网站 这里 然后就是按照他说的步骤去做. 第1步 安装  pip3 install tinydb 安装成功后,创建一个文件名字叫做 tes ...