每个服务端点的 HttpClient 实例

HttpClient Instancing Per Service-Endpoint

实例化 HttpClient 时,一个常见的建议是:

但是,基于 on this link 我看到的评论暗示了另一条规则:

The HttpClient class instance acts as a session to send HTTP requests. An HttpClient instance is a collection of settings applied to all requests executed by that instance. In addition, every HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.

这让我想知道我是否应该为与之交互的每个服务端点创建一个 HttpClient 实例。 "service-endpoint" 是指不同的基地址。以下每一项都是不同的 "service-endpoint":

当然,如果我打算使用 HttpClient 的 "BaseAddress" 属性,并且如果我正在处理并发调用,那么我将需要每个 [=52] 有一个 HttpClient 实例=].

但是,HttpClient 确实允许我明确指定一个绝对地址:

HttpClient client = new HttpClient(...);

client.PostAsJsonAsync("http://foo.net/api/Message/", ...);
client.PostAsJsonAsync("http://bar.com/api/Message/", ...);
client.PostAsJsonAsync("http://wow.gov/api/Message/", ...);
client.PostAsJsonAsync("http://now.com/api/Message/", ...);
client.PostAsJsonAsync("http://mom.org/api/Message/", ...);
client.PostAsJsonAsync("http://dog.com/api/Message/", ...);

以上代码有效,这正是我正在构建的当前应用程序所需要的。但令人烦恼的问题仍然存在……如果我对我的应用程序与之通信的所有服务端点使用一个 HttpClient,我是否做错了什么?

为什么我真的需要上面引文中提到的 "connection pool isolation"?

But I want to know if I will be compromising the inner workings of HttpClient because I'm making many endpoints share the same connection pool.

不,我认为 HttpClient 的单个实例不会耗尽您的资源,但这实际上取决于您将发出多少并发请求。 HttpClient 旨在为并发请求提供服务,通过使用异步 API 这样的 (XXXAsync),您可以实现这一点。

我建议不要忘记将 ServicePointManager.DefaultConnectionLimit 设置为更大的数字,因为它的默认值为 2(并发请求)。

此外,如果您认为单个实例很快就会遇到瓶颈,我建议您一如既往地分析您的应用程序以了解确切的瓶颈。

我也遇到了同样的问题

还有我调查的结果:

  1. 如果您需要在请求期间更改其非线程安全设置 (DefaultRequestHeaders, BaseAddress),请使用单独的 HttpClient 实例。使用每个实例的一组特定设置创建单独的实例将是有用且安全的。更多细节:HttpClient–Is It Really Thread-Safe?

  2. 好的,我创建了 HttpClient 的特定实例,但我不想使用 BaseAdress。从第 1 点开始,我需要为每个唯一 BaseAdress(主机)使用新的 HttpClient 实例。

    但是,如果我使用 HttpClient 来请求多个主机,而没有 BaseAdress 绝对地址呢? 您可以跟踪从 HttpClientSocketsHttpHanlder 再到 HttpConnectionPoolManager (dotnet source code) 的调用,并看到它为每个主机创建单独的 'HttpConnectionPool' 并将池添加到 'ConcurrentDictionary' _池。这意味着无论如何我们为每个唯一的主机都有单独的池。 这就是为什么我更喜欢在没有 BaseAdress 用法的情况下为多个主机使用单个 HttpClient 实例。