HttpClientFactory in ASP.NET Core 2.1 Part 1 介绍
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 show 和 ASP.NET Community Standup。Ryan Nowak 的建议是,他是 ASP.NET 主力团队中该功能的开发者之一,是现在已经足够稳定可以基于它开发开发了。
注:请注意到本文是在官方预览发布之前撰写的,进而,在正式发布的时候,情况可能发生了一些变化,
什么是 HttpClientFactory?
在 ASP.NET 团队的词汇里,它是 用来创建 HttpClient 实例的工厂,并且是伴随 ASP.NET Core 2.1 发布带来的新特性。基于你过去使用 HttpClient 的体验,你可能遇到也可能没有遇到一些问题,有时甚至你没有感到是问题。
第一个问题是,当你在应用中创建多个 HttpClient 实例的时候,你会遇到两个问题:
- 它是低效的,因为每个都会针对远程服务器拥有自己的连接池。这意味着你会在每个客户端每次重新连接到远程服务器的时候花费代价。
- 更大的问题是,如果你创建了大量的 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 介绍的更多相关文章
- ASP.NET Core 中的 Razor 页面介绍
标题:ASP.NET Core 中的 Razor 页面介绍 地址:https://docs.microsoft.com/zh-cn/aspnet/core/razor-pages/index?view ...
- ASP.NET Core 应用程序Startup类介绍
Startup类配置服务和应用程序的请求管道. Startup 类 ASP.NET Core应用程序需要一个启动类,按照惯例命名为Startup.在主程序的Web Host生成器(WebHostBui ...
- asp.net core系列 53 IdentityServer4 (IS4)介绍
一.概述 在物理层之间相互通信必须保护资源,需要实现身份验证和授权,通常针对同一个用户存储.对于资源安全设计包括二个部分,一个是认证,一个是API访问. 1 认证 认证是指:应用程序需要知道当前用户的 ...
- ASP.NET Core 应用程序Startup类介绍 (转载)
Startup类配置服务和应用程序的请求管道. Startup 类 ASP.NET Core应用程序需要一个启动类,按照惯例命名为Startup.在主程序的Web Host生成器(WebHostBui ...
- asp.net core系列 72 Exceptionless使用介绍
一.Exceptionless介绍 Exceptionless专注于.net平台提供实时错误和日志报告.主要包括:错误通知.智能分组异常.详细错误报告堆栈跟踪.支持离线.UI查看重要错误和确定优先级. ...
- ASP.NET Core 中的 依赖注入介绍
ASP.NET Core 依赖注入 HomeController public class HomeController : Controller { private IStudentReposito ...
- ASP.NET Core身份认证服务框架IdentityServer4 介绍
IdentityServer4是ASP.NET Core 2的OpenID Connect和OAuth 2.0框架.它可以在您的应用程序中提供以下功能: 它使你的应用程序具有如下特点: 认证即服务 适 ...
- 菜鸟入门【ASP.NET Core】9:RoutingMiddleware介绍以及MVC引入
前言 前面介绍了使用app.Map来配置路由,但是对于一般不是特别大的项目来说,不使用Map来进行路由配置. 配置路由 我们首先需要在Startup.cs文件中的ConfigureServices方法 ...
- asp.net core系列 65 正反案例介绍SOLID原则
一.概述 SOLID五大原则使我们能够管理解决大多数软件设计问题.由Robert C. Martin在20世纪90年代编写了这些原则.这些原则为我们提供了从紧耦合的代码和少量封装转变为适当松耦合和封装 ...
- asp.net core网关Ocelot的简单介绍& Ocelot集成Identity认证
文章简介 Ocelot网关简介 Ocelot集成Idnetity认证处理 Ocelot网关简介 Ocelot是一个基于netcore实现的API网关,本质是一组按特定顺序排列的中间件.Ocelot内 ...
随机推荐
- Adobe Acrobat XI Pro 打开pdf报错 109
事件起因: 某同事在使用 Adobe Acrobat XI Pro 打开pdf文件时,会偶发性的报错 "处理页面时发生错误.读取本文当时出现问题(109)." 解决办法: 在网 ...
- Java如何将Object转换成指定Class对象
在Java中,将Object转换为指定类型的Class对象实际上是两个不同概念的操作: 将Object实例转换为特定类型的实例:这通常涉及到类型转换(如(MyType) myObject)或者通过反射 ...
- 共124篇!墨天轮“高可用架构”干货文档分享(含Oracle、MySQL、PG)
大家期待的高可用篇来啦!在上期<墨天轮高分技术文档分享-Oracle升级迁移篇>中大家对数据库高可用架构相关文档呼声较高,这不就来啦! 数据库的高可用架构能够在发生宕机或意外中断等故障时起 ...
- 7-11 leetcode 2612
请你编写一个异步函数,它接收一个正整数参数 millis ,并休眠这么多毫秒.要求此函数可以解析任何值. ps: promise 期约函数 (异步函数)的使用 ,promise 是一个对象 new ...
- 03-jsx中使用js表达式
// 在jsx中使用 js 表达式 /// 通过一个 {} 展示变量即可 vue 中使用 {{}} 展示js表达式 // 什么是js表达式 有结果的 import reactDom from &quo ...
- Acrobat DC安装报错1603,Microsoft Visual C++2013(x64)失败
之前顺利安装过Acrobat DC,但可能因为自动更新了,导致让我重新登录才能使用,无法再次破解.于是我卸载后重新安装,发现提示Microsoft Visual C++2013(x64)运行安装失败. ...
- FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
<FFmpeg开发实战:从零基础到短视频上线>一书的"5.1.2 把音频流保存为PCM文件"介绍了如何把媒体文件中的音频流转存为原始的PCM音频,在样例代码的转存过 ...
- Uniswap V2 核心 合约代码
Uniswap V2 核心 UniswapV2Factory UniswapV2Pair UniswapV2ERC20 IUniswapV2Router02 1. UniswapV2Factory 合 ...
- ABC372 (D,E)
ABC372 (D,E) D 一道比较简单的二分查找题目. 观察到每个数能成为 \(j\) 的条件是独立的,因此想到统计每个数能成为它前面哪些数的 \(j\). 对于每个\(ed\), 二分 \(1 ...
- 2.13 新手必读的Linux使用注意事项
通过安装并体验 Linux 系统,读者应该能发现 Linux 与 Windows 的一些不同之处,本节就几个容易让初学者混淆的问题做重点讲解,以便加深读者对 Linux 系统的认识. Linux 严格 ...