在 WebAPI 客户端中每次调用创建一个新的 HttpClient 的开销是多少?

What is the overhead of creating a new HttpClient per call in a WebAPI client?(在 WebAPI 客户端中每次调用创建一个新的 HttpClient 的开销是多少?)
本文介绍了在 WebAPI 客户端中每次调用创建一个新的 HttpClient 的开销是多少?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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 的开销是多少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)