为啥在 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 是错误的?的主要内容,如果未能解决你的问题,请参考以下文章