几天来我一直在努力尝试在使用 HttpClient 时阻止池中的多个连接
我构建了一个 REST WebApi,我通过在其中使用 HttpClient 从中调用外部端点。 Controller 的 Action 被客户端多次调用以执行上述外部调用。
以前我使用的是 WebClient,但在发出多个请求时它会遇到 SocketExhaustation 问题。在网络上搜索我发现如果静态使用或在单例中使用,迁移到 HttpWebClient 将解决我的问题。我什至尝试实现 IHttpClientFactory 但它没用,因为我在注入(inject)的服务中遇到了同样的问题。
这是我目前的实现,经过多次重构。很抱歉,如果目前这段代码不是最佳的,但在多次重写之后,这是我最后的选择。
public static class CustomHttpClientManager
{
private static HttpClient _httpClient;
public static void Initialize()
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;
CookieContainer cookies = new CookieContainer();
_httpClient = new HttpClient(
new SocketsHttpHandler()
{
Proxy = new CustomProxy(),
UseProxy = true,
PooledConnectionLifetime = TimeSpan.FromSeconds(30),
PooledConnectionIdleTimeout = TimeSpan.FromSeconds(20),
MaxConnectionsPerServer = 2,
CookieContainer = cookies,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
});
_httpClient.DefaultRequestHeaders.ConnectionClose = false;
}
public static async Task<string> GetAsString(string url){
HttpResponseMessage response = null;
try{
HttpRequestMessage httpRequestMessage = new HttpRequestMessage()
{
RequestUri = new Uri(url),
Method = HttpMethod.Get
};
httpRequestMessage.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
httpRequestMessage.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
httpRequestMessage.Headers.Add("Accept-Language", "en-GB,en-US;q=0.8,en;q=0.6");
httpRequestMessage.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
response = await _httpClient.SendAsync(httpRequestMessage);
if(response.IsSuccessStatusCode){
return await response.Content.ReadAsStringAsync();
}
else{
throw new Exception(ex.Message);
}
}
catch(Exception ex){
return $"Could not fetch response from: {connectionParameters.Url}, due to: {ex.Message}";
}
finally{
if(response != null){
response.Dispose();
}
}
}
}
到达当前代码之前的调用栈是这样的:
CustomHttpClientManager
的 Initialize
方法,该方法仅实例化 HttpClient
一次。CustomHttpClientManager
的GetAsString
方法通过使用先前实例化的HttpClient
执行外部调用客户端对 WebApi 执行大量调用(每分钟约 200 rq),当在命令提示符下运行 netstat -ano
时,它会显示一个相当长的池连接列表,其状态是 TIME_WAIT,这表明 HttpClient
根本没有重用池中的连接。这些连接仅在使用后 2 分钟左右消失。
除了这段代码,我还有其他方法。
.AddHttpClient()
在启动时注入(inject) IHttpClientFactory
它们都不起作用。我不知道还能做什么。这让我连续两天都发疯了。
我已经从一个简单的控制台应用程序测试了这个实现,但问题没有发生。这向我表明,一旦给出对其调用者的答复,WebApi 操作就会以某种方式不断关闭外部连接,并且一旦进行了另一个调用,它就会在池中创建另一个连接,并且它也会继续处理下一个传入请求。
顺便说一句,我正在使用 .NET Core 3.1
提前致谢
最佳答案
使用
PooledConnectionLifetime = TimeSpan.FromSeconds(30),
表示连接在 30 秒后从池中删除。
您可以将其更改为更长的时间(例如 10 分钟)- 机器人不会太长以适应 DNS 更改。
关于c# - 连接池中处于 TIME_WAIT 状态的许多连接,在 WebApi 中使用静态或单个 HttpClient 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63846914/