为啥在 WebApi 上下文中的 using 块中使用 HttpClient 是错误的?
Posted
技术标签:
【中文标题】为啥在 WebApi 上下文中的 using 块中使用 HttpClient 是错误的?【英文标题】:Why using HttpClient in a using block IS WRONG in WebApi context?为什么在 WebApi 上下文中的 using 块中使用 HttpClient 是错误的? 【发布时间】:2021-04-16 14:46:44 【问题描述】:那么,问题是为什么在 using 块中使用 HttpClient 是错误的,但在 WebApi 上下文中?
我一直在阅读这篇文章Don't Block on Async Code。在其中我们有以下示例:
public static async Task<JObject> GetJsonAsync(Uri uri)
// (real-world code shouldn't use HttpClient in a using block; this is just example code)
using (var client = new HttpClient())
var jsonString = await client.GetStringAsync(uri);
return JObject.Parse(jsonString);
// My "top-level" method.
public class MyController : ApiController
public string Get()
var jsonTask = GetJsonAsync(...);
return jsonTask.Result.ToString();
// (real-world code shouldn't use HttpClient in a using block; this is just example code)
的评论刚刚触发了我。我一直都是这样使用HttpClient的。
我检查的下一件事是Microsoft's documentation on HttpClient Class。 在其中,我们有以下语句以及提供的源示例:
HttpClient 旨在被实例化一次并在整个过程中重复使用 应用程序的生命周期。实例化一个 HttpClient 类 每个请求都将耗尽大量可用的套接字数量 负载。这将导致 SocketException 错误。下面是一个例子 正确使用 HttpClient。
public class GoodController : ApiController
private static readonly HttpClient HttpClient;
static GoodController()
HttpClient = new HttpClient();
那么是不是每次请求都会调用构造函数,因此每次都会创建一个新的HttpClient?
谢谢!
【问题讨论】:
【参考方案1】:这个答案有点长……
最初,官方建议在using
块中使用HttpClient
。但是这个caused problems at scale,本质上是在TIME_WAIT
状态下消耗了大量的连接。
所以,官方建议改为使用静态HttpClient
。但这会导致it would never correctly handle DNS updates 出现问题。
因此,ASP.NET 团队提出了IHttpClientFactory
in .NET Core 2.1,因此代码(或至少在现代平台上运行的代码)可以重用HttpClient
实例(或者更准确地说,是消息处理程序 这些实例),避免 TIME_WAIT
问题,但也定期关闭这些连接以避免 DNS 问题。
但是,同时,.NET 团队提出了SocketsHttpHandler
also in .NET Core 2.1,也做了连接池。
因此,在现代平台上,您可以使用IHttpClientFactory
或静态/单例HttpClient
。在较旧的平台(包括 .NET Framework)上,您将使用静态/单例 HttpClient
并解决 DNS 问题或 use other workarounds。
【讨论】:
感谢您的精彩解释!确实比我预期的要多。【参考方案2】:实际上在写这个问题时,我注意到微软提供的代码示例中的静态构造函数。现在这一切都说得通了。
Static Constructors 用于初始化任何静态数据,或执行只需要执行一次的特定操作。在创建第一个实例或引用任何静态成员之前自动调用它。
在 WebAPI 的上下文中,静态构造函数被调用一次,因此只创建一个 HttpClient 并将其重用于所有其他请求。
我再也不会在生产代码中使用using(HttpClient....)
。
这是一篇关于 HttpClient 错误使用的好文章 - YOU'RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE
【讨论】:
另见优秀文章:You're Using HttpClient Wrong,You're using HttpClient wrong and it is destabilizing your software,You're (probably still) using HttpClient wrong and it is destabilizing your software 谢谢,刚刚想起另一篇与该主题相关的好文章。以上是关于为啥在 WebApi 上下文中的 using 块中使用 HttpClient 是错误的?的主要内容,如果未能解决你的问题,请参考以下文章
为啥条件块中的函数声明在 Chrome 而不是 Firefox 中提升到函数范围?