【发布时间】:2020-08-01 09:24:08
【问题描述】:
我们正在和朋友一起做一个有趣的项目,我们必须执行数百个 HTTP 请求,所有这些请求都使用不同的代理。想象一下它是这样的:
for (int i = 0; i < 20; i++)
{
HttpClientHandler handler = new HttpClientHandler { Proxy = new WebProxy(randomProxy, true) };
using (var client = new HttpClient(handler))
{
using (var request = new HttpRequestMessage(HttpMethod.Get, "http://x.com"))
{
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
}
}
using (var request2 = new HttpRequestMessage(HttpMethod.Get, "http://x.com/news"))
{
var response = await client.SendAsync(request2);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
}
}
}
}
顺便说一下,我们使用的是 .NET Core(目前是控制台应用程序)。我知道有很多关于套接字耗尽和处理 DNS 回收的线程,但是这个特定的线程是不同的,因为使用了多个代理。
如果我们使用 HttpClient 的单例实例,就像大家建议的那样:
- 我们不能设置多个代理,因为它是在 HttpClient 实例化期间设置的,之后无法更改。
- 它不考虑 DNS 更改。重用 HttpClient 的实例意味着它会保留套接字直到它关闭,因此如果服务器上发生 DNS 记录更新,客户端将永远不会知道,直到该套接字关闭。一种解决方法是将
keep-alive标头设置为false,以便在每次请求后关闭套接字。它导致次优性能。第二种方法是使用ServicePoint:
ServicePointManager.FindServicePoint("http://x.com")
.ConnectionLeaseTimeout = Convert.ToInt32(TimeSpan.FromSeconds(15).TotalMilliseconds);
ServicePointManager.DnsRefreshTimeout = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds);
另一方面,处理 HttpClient(就像我上面的示例一样),即 HttpClient 的多个实例,会导致多个套接字处于 TIME_WAIT 状态。 TIME_WAIT 表示本地端点(这边)已经关闭了连接。
我知道SocketsHttpHandler 和IHttpClientFactory,但它们无法解决不同的代理问题。
var socketsHandler = new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(10),
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(5),
MaxConnectionsPerServer = 10
};
// Cannot set a different proxy for each request
var client = new HttpClient(socketsHandler);
可以做出的最明智的决定是什么?
【问题讨论】:
-
HttpClientFactory 修复了所有的 dns 和 socket 耗尽问题
-
'但他们无法解决不同的代理问题。' - 这是什么意思
-
为每个代理创建一个单独的 httpclient 实例并重用它?
-
注意:
ServicePointManager不会影响 .NET Core 中的HttpClient,因为它打算与HttpWebRequest一起使用,而 .NET Core 中的HttpClint不使用它。 NET 核心。是的,每个代理的HttpClient实例看起来是合理的解决方案。IHttpClientFactory将同时修复socket和dns问题。 -
@aepot,哦,那是真的。我忘了在 HttpResponseMessage 上添加使用。我经常会收到不成功的代码。我会添加
HttpCompletionOption.ResponseHeadersRead。
标签: c# .net-core httpclient time-wait