问题描述
WebAPI 客户端的 HttpClient
生命周期应该是多少?HttpClient
的一个实例用于多次调用会更好吗?
What should be the HttpClient
lifetime of a WebAPI client?
Is it better to have one instance of the HttpClient
for multiple calls?
每个请求创建和处理 HttpClient
的开销是多少,如下例所示(取自 http://www.asp.net/web-api/overview/web-api-clients/call-a-web-api-from-a-net-client):
What's the overhead of creating and disposing a HttpClient
per request, like in example below (taken from http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client):
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:9000/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// New code:
HttpResponseMessage response = await client.GetAsync("api/products/1");
if (response.IsSuccessStatusCode)
{
Product product = await response.Content.ReadAsAsync<Product>();
Console.WriteLine("{0} ${1} {2}", product.Name, product.Price, product.Category);
}
}
推荐答案
HttpClient
已设计为可重复用于多次调用.甚至跨多个线程.HttpClientHandler
具有旨在跨调用重复使用的凭据和 Cookie.拥有一个新的 HttpClient
实例需要重新设置所有这些东西.此外,DefaultRequestHeaders
属性包含用于多次调用的属性.必须在每个请求上重置这些值是不正确的.
HttpClient
has been designed to be re-used for multiple calls. Even across multiple threads.
The HttpClientHandler
has Credentials and Cookies that are intended to be re-used across calls. Having a new HttpClient
instance requires re-setting up all of that stuff.
Also, the DefaultRequestHeaders
property contains properties that are intended for multiple calls. Having to reset those values on each request defeats the point.
HttpClient
的另一个主要好处是能够将 HttpMessageHandlers
添加到请求/响应管道中以应用横切关注点.这些可以用于日志记录、审计、节流、重定向处理、离线处理、捕获指标.各种不同的东西.如果在每个请求上创建一个新的 HttpClient,则需要在每个请求上设置所有这些消息处理程序,并且还需要提供在这些处理程序的请求之间共享的任何应用程序级状态.
Another major benefit of HttpClient
is the ability to add HttpMessageHandlers
into the request/response pipeline to apply cross cutting concerns. These could be for logging, auditing, throttling, redirect handling, offline handling, capturing metrics. All sorts of different things. If a new HttpClient is created on each request, then all of these message handlers need to be setup on each request and somehow any application level state that is shared between requests for these handlers also needs to be provided.
您使用 HttpClient
的功能越多,您就越会发现重用现有实例是有意义的.
The more you use the features of HttpClient
, the more you will see that reusing an existing instance makes sense.
然而,我认为最大的问题是,当一个 HttpClient
类被释放时,它会释放 HttpClientHandler
,然后强制关闭 TCP/IP
连接池中由 ServicePointManager
管理的连接.这意味着每个带有新 HttpClient
的请求都需要重新建立一个新的 TCP/IP
连接.
However, the biggest issue, in my opinion is that when a HttpClient
class is disposed, it disposes HttpClientHandler
, which then forcibly closes the TCP/IP
connection in the pool of connections that is managed by ServicePointManager
. This means that each request with a new HttpClient
requires re-establishing a new TCP/IP
connection.
根据我的测试,在 LAN 上使用纯 HTTP,性能影响可以忽略不计.我怀疑这是因为即使 HttpClientHandler
试图关闭它,也有一个底层 TCP keepalive 保持连接打开.
From my tests, using plain HTTP on a LAN, the performance hit is fairly negligible. I suspect this is because there is an underlying TCP keepalive that is holding the connection open even when HttpClientHandler
tries to close it.
对于通过互联网发送的请求,我看到了不同的故事.由于每次都必须重新打开请求,我发现性能下降了 40%.
On requests that go over the internet, I have seen a different story. I have seen a 40% performance hit due to having to re-open the request every time.
我怀疑对 HTTPS
连接的攻击会更糟.
I suspect the hit on a HTTPS
connection would be even worse.
我的建议是在应用程序的整个生命周期内为您连接的每个不同的 API 保留一个 HttpClient 实例.
这篇关于在 WebAPI 客户端中每次调用创建一个新的 HttpClient 的开销是多少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!