多个API服务的.Net Core HttpClientFactory

12

我有一个 .Net Core 项目需要连接约4个不同的API服务,虽然我对HttpClient代码并不是很熟悉,但从我找到的资料来看,通常情况下你只想重用一个HttpClient实例。据我所知,.Net Core中普遍认为应该使用HttpClientFactory,在启动类中注册并通过DI请求。

现在除了BaseAddress url之外,我的大多数默认标头和类似内容都是相同的,那么当连接到4个不同的API服务时,我该如何处理呢?我应该注册4个不同的命名客户端还是拥有一个已预设所有默认信息的客户端,然后根据需要手动进行配置,例如配置地址?

通常问题是,因为我还比较新手,所以应该重复使用一个HttpClient实例。

  1. 如果我为每个API服务创建4个不同的命名客户端,那么当我调用.CreateClient()方法时,这是否会创建4个HttpClient实例?
  2. .CreateClient()每次被调用时都会创建一个新的实例,如果我需要对同一个API服务进行3个不同的调用,每个调用都将调用.CreateClient()建立某种连接,那么这不就打败了只保留一个HttpClient实例的目的吗?

感谢任何有助于澄清的帮助,

谢谢!


3
您有几个选项,只需注册IHttpClientFactory,并在调用factory.CreateClient()时添加标头,或者创建一个包含所需标头的命名客户端,并使用factory.CreateClient("namedclient"),两种方法都非常简单,选择哪一种几乎没有任何区别。 - TheGeneral
4
请查看IHttpClientFactory使用模式的文档。如果您不介意使用第三方库,那么使用Refit生成的客户端是非常简单的解决方案。否则,命名或类型化的客户端也可以工作。 - devNull
1
@MichaelRandall 啊,好的,那么当我需要进行 API 调用时,每次实际调用 factory.CreateClient() 时,我想我们必须要调用它。这样做会创建多个 HttpClient 实例吗?还是需要进行 If() 检查并检查 httpClient 是否为 null,然后再创建,否则就直接返回它?我只是不太明白这如何解决重复使用一个 HttpClient 实例的问题? - SC.Cee
3
IHttpClientFactory是对普通HttpClient存在的所有问题进行改进的。简而言之,您可以安全地调用CreateClient多次,并在底层为您处理所有操作(实际上这是推荐的方式,除非您有一个非常特定的使用情况),无需缓存客户端,所有生成的客户端都是线程安全的。 - TheGeneral
1
IHttpClientFactory.CreateClient 文档的备注中可知:每次调用 CreateClient(String) 都会返回一个新的 HttpClient 实例。调用者可以无限期地缓存返回的 HttpClient 实例或在需要时使用 using 块将其处理掉。默认的 IHttpClientFactory 实现可能会缓存底层的 HttpMessageHandler 实例以提高性能。 调用者也可以自由地改变返回的 HttpClient 实例的公共属性。(强调为我)。 - CoolBots
啊,我明白了,谢谢大家的澄清。 - SC.Cee
1个回答

6
使用 IHttpClientFactory 的目的不是为了重用 HttpClient 实例,而是通过池化来重用(HttpClientHandler 的派生类) HttpMessageHandler 实例,该实例是管理 HTTP 连接和套接字的基础对象。微软文档中的这张图很好地阐述了这一点。
您可能会担心频繁调用 IHttpClientFactory.CreateClient() 会产生与频繁调用 new HttpClient() 相同的问题。然而,情况并非如此。正如Microsoft 文档所解释的那样,频繁调用 new HttpClient() 会导致套接字耗尽,因为这个构造函数将创建一个新的 HttpMessageHandler 实例:

但是,问题并不是 HttpClient 本身,而是 HttpClient 的默认构造函数,因为它创建了一个新的 HttpMessageHandler 具体实例,该实例是上述套接字耗尽和 DNS 更改问题的根源。

您可以从 IHttpClientFactory源代码中看到,它不使用 CreateClient()HttpClient 的无参数构造函数。相反,它从池中获取 HttpMessageHandler 并将其注入到创建的 HttpClient 中。
无论您是使用类型化客户端还是命名客户端,都应将 HttpClient 实例视为瞬态对象:它很容易创建,而且不需要长时间缓存。

@scarnyw 如果将'factory.CreateClient()'作为参数传递给“helper”类库中的方法,而不是在DI容器中注册该类库作为服务,会怎样呢? - Baked Inhalf
自从.NET Core 2.1版本以来,HttpClient默认使用的消息处理程序实际上是SocketsHttpHandler而非HttpClientHandler - Etienne de Martel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接