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. MySQL笔记--数据库定时备份与恢复

    利用crontab定时.利用mysqldump备份 编写sh启动脚本时记得赋予执行权限(x) 如果没有mysqldump命令执行,基于centos7 yum -y install mysql-clie ...

  2. WPF下使用FreeRedis操作RedisStream实现简单的消息队列

    Redis Stream简介 Redis Stream是随着5.0版本发布的一种新的Redis数据类型: 高效消费者组:允许多个消费者组从同一数据流的不同部分消费数据,每个消费者组都能独立地处理消息, ...

  3. 在C#中使用适配器Adapter模式和扩展方法解决面向的对象设计问题

    之前有阵子在业余时间拓展自己的一个游戏框架,结果在实现的过程中发现一个设计问题.这个游戏框架基于MonoGame实现,在MonoGame中,所有的材质渲染(Texture Rendering)都是通过 ...

  4. vue3自动导入 api ,不需要多次导入 api 了

    安装插件   npm i -D unplugin-auto-import 配置 vite.config.js export default defineConfig({ plugins: [ vue( ...

  5. Android复习(四)权限—>请求应用权限

    每款 Android 应用都在访问受限的沙盒中运行.如果应用需要使用其自己的沙盒外的资源或信息,则必须请求相应权限. 要声明您的应用需要某项权限,您可以在应用清单中列出该权限,然后在运行时请求用户批准 ...

  6. Docker挂载jar包运行脚本

    下载镜像 docker pull openjdk:8 执行命令 docker run -d -p 9001:8081 -v /opt/springboot-docker-1.0.jar:/var/li ...

  7. ASP.NET实现网站发布及跨域访问

    1.软件下载及安装 visual studio 2012 or 2013 启用电脑IIS配置 2.网页编写及排版 在visual studio中创建web项目添加aspx页面(个人网页:和html差不 ...

  8. Linux中ln 链接命令的用法

    ln的语法 Usage: ln [OPTION]... [-T] TARGET LINK_NAME (1st form) or: ln [OPTION]... TARGET (2nd form) or ...

  9. 基于云原生的私有化 PaaS 平台交付实践

    作者:牛玉富,某知名互联网公司专家工程师.喜欢开源 / 热衷分享,对 K8s 及 golang 网关有较深入研究. 本文将解读如何利用云原生解决私有化交付中的问题,进而打造一个 PaaS 平台,提升业 ...

  10. appium环境搭建及命令行启动sdk模拟器-附踩坑以及解决过程

    安装教程这里就不阐述了,网上一大堆教程,下载完成后安装然后配置对应的环境变量即可 android sdk及java home配置: path配置: %ANDROID_HOME%\platform-to ...