.NET HttpClient的缺陷
using (HttpClient client = new HttpClient()){}
每次发起http请求每次new httpClient,它会打开许多套接字,比你实际的需求多许多,这极大地增加了服务器的负载。而且,这些套接字实际上不会被using语句关闭。相反,它们是在应用程序停止使用它们几分钟之后才会关闭。
当你销毁它时,它就启动一个进程,关闭在它控制之下的套接字。也就是说,你下次请求连接时,必须重复整个连接新建过程。如果网络延迟很高,或者连接是受保护的(需要新一轮的SSL/TLS协商),就会非常痛苦。
关闭一个套接字需要花费4分钟,关闭套接字的过程并不快。当“关闭”套接字时,你真正做的是将其状态置为TIME_WAIT。在一个预先配置好的时间窗口内,Windows将保持该套接字的状态不变,默认情况下是4分钟。这是为了防止有任何剩余的数据包仍在传输。
这大大增加了可用套接字耗尽的可能,导致运行时错误,比如“无法连接到远程服务器。System.Net.Sockets.SocketException:每个套接字地址(协议/网络地址/端口)通常只允许使用一次”。
Microsoft P&P建议创建一个HttpClient实例,把它存储在一个静态字段中,并在应用程序的生存期内共享该实例,而不是根据需求创建和销毁。
public class GoodController : ApiController { // OK private static readonly HttpClient HttpClient; static GoodController() { HttpClient = new HttpClient(); } } You create a single static instance of HttpClient. In console or desktop applications, you can expose this instance just about anywhere. In an ASP.NET Web API application, you can create it in the Global.asax.cs file. namespace HttpClientGuidance { public class WebApiApplication : System.Web.HttpApplication { internal static HttpClient httpClientInstance; protected void Application_Start() { GlobalConfiguration.Configure(WebApiConfig.Register); Uri baseUri = new Uri("https://someresource.com"); httpClientInstance = new HttpClient(); httpClientInstance.BaseAddress = baseUri; httpClientInstance.DefaultRequestHeaders.Clear(); httpClientInstance.DefaultRequestHeaders.ConnectionClose = false; httpClientInstance.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); ServicePointManager.FindServicePoint(baseUri).ConnectionLeaseTimeout = 60 * 1000; } } }
欢迎关注公众号:DotNet软件编程IT技术
欢迎关注公众号:DotNet软件编程IT技术