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. 2021年10月国产数据库排行榜-墨天轮:达梦反超OceanBase夺榜眼,TDSQL实现“四连增”,数据生态加速建设

    2021年10月国产数据库排行榜已在墨天轮发布,本月共有150家数据库参与排名.我们可以用"半江瑟瑟半江红"来形容10月份数据库分数涨跌情况.除去分数没有变化的数据库,分数上涨和下 ...

  2. C#的函数使用 和参数修饰符 out ref params

    // 函数和方法 // 函数好比对象的动作行为 在定义函数的时候,职责(作用/功能)越单一越好 满足高内聚 低耦合的开发思路 // 变量的命名规则 小驼峰 // 函数的命名规则 大驼峰 动词开头 // ...

  3. 66.有没有碰到过数组响应丢失(问的是ref和reactive的用法,什么情况下用)

    由于vue3使用proxy,对于对象和数组都不能直接整个赋值.  直接赋值丢失了响应性 只有push或者根据索引遍历赋值才可以保留reactive数组的响应性  : 可以使用 toRefs 解决这个问 ...

  4. ide 安装eval reset插件 Pycharm 永久破解

    ide 安装eval reset插件 Pycharm 永久破解 1.安装eval reset的目的 Jetbrains家的产品有一个很良心的地方,他会允许你试用30天(这个数字写死在代码里了)以评估是 ...

  5. rocketmq安全漏洞

    漏洞内容 服务器支持 TLS Client-initiated 重协商攻击(CVE-2011-1473)[原理扫描] 该漏洞存在于SSL renegotiation的过程中.对于使用SSL重协商功能的 ...

  6. 浅谈 K-D Tree 及其进阶应用

    前言 \(\text{K-D Tree (K-Dimension Tree)}\) 是一种可以有效处理高维信息的数据结构. 在一般信息学竞赛题目中 \(k = 2\),此时它又称 \(\text{2- ...

  7. WTConv:小参数大感受野,基于小波变换的新型卷积 | ECCV'24

    近年来,人们尝试增加卷积神经网络(CNN)的卷积核大小,以模拟视觉Transformer(ViTs)自注意力模块的全局感受野.然而,这种方法很快就遇到了上限,并在实现全局感受野之前就达到了饱和.论文证 ...

  8. MaskGCT,AI语音克隆大模型本地部署(Windows11),基于Python3.11,TTS,文字转语音

    前几天,又一款非自回归的文字转语音的AI模型:MaskGCT,开放了源码,和同样非自回归的F5-TTS模型一样,MaskGCT模型也是基于10万小时数据集Emilia训练而来的,精通中英日韩法德6种语 ...

  9. spring下 -spring整体架构,JdbcTemplate笔记

    2,搭建Java Maven项目 我的idea是2024.1.1版本,创建普通Maven项目如下图: 用的jdk8,项目名可以自己改,Archetype选图中的第一个就行,之后点 create. 创建 ...

  10. CF980-Div2-D

    CF980-Div2-D 题意 从 \(1\) 开始决策,若选当前数,则累计贡献 \(a[i]\) 并跳到 \(j\) 位置,\(j\) 是 \(\lt i\) 且没有决策过(包括选了和没选)的最大位 ...