我已经阅读了一些文章以及使用静态HttpClient和解决方案的缺陷。其中一篇文章是 - http://byterot.blogspot.ca/2016/07/singleton-httpclient-dns.html
我已经实施了解决方案,并希望进行测试以确保文章提出的实际工作方式。
以下是我们试图避免的代码:
Task.Run(async () =>
{
using (var httpClient = new HttpClient(new ApiHandler()))
{
var httpResponse = await httpClient.GetAsync("https://test.com/api/Tiers");
var result = await httpResponse.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}).ContinueWith(async task =>
{
await Task.Delay(5000);
using (var httpClient = new HttpClient(new ApiHandler()))
{
var httpResponse = await httpClient.GetAsync("https://test.com/api/Tiers");
var result = await httpResponse.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}).ContinueWith(async task =>
{
await Task.Delay(10000);
using (var httpClient = new HttpClient(new ApiHandler()))
{
var httpResponse = await httpClient.GetAsync("https://test.com/api/Tiers");
var result = await httpResponse.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
});
当我查看fiddler中的流量时:
行为如预期。每个创建和部署都强制在请求和响应完成时建立连接。
使用HttpClient的正确和建议的方法是使它成为静态的:
private static readonly HttpClient HttpClient = new HttpClient(new ApiHandler());
static void Main()
{
ServicePointManager
.FindServicePoint(new Uri("https://test.com"))
.ConnectionLeaseTimeout = 1000; // 1 second
ServicePointManager.DnsRefreshTimeout = 1000; // 1 second
Task.Run(async () =>
{
var httpResponse = await HttpClient.GetAsync("https://test.com/api/Tiers");
var result = await httpResponse.Content.ReadAsStringAsync();
Console.WriteLine(result);
}).ContinueWith(async task =>
{
await Task.Delay(5000); // delay 5 seconds
var httpResponse = await HttpClient.GetAsync("https://test.com/api/Tiers");
var result = await httpResponse.Content.ReadAsStringAsync();
Console.WriteLine(result);
}).ContinueWith(async task =>
{
await Task.Delay(10000); // delay 10 seconds
var httpResponse = await HttpClient.GetAsync("https://test.com/api/Tiers");
var result = await httpResponse.Content.ReadAsStringAsync();
Console.WriteLine(result);
});
Console.ReadKey();
}
我期望与上一张图片具有相同的行为,但它看起来如下:
如果我然后添加HttpClient.DefaultRequestHeaders.ConnectionClose = true;
,我会得到所需的结果,但这是我们想要避免的 - 对于每个创建连接的请求响应。
我对Fiddler的理想结果是正确的吗?或者我错过了设置ConnectionLeaseTimeout
和/或DnsRefreshTimeout
的内容?我真的很想测试这种行为,并确保在ServicePointManager
上设置这些属性可以解决HttpClient静态实例的已知DNS问题。
答案 0 :(得分:3)
Fiddler将自己注册为代理。默认情况下,它侦听127.0.0.1,端口8888.因此,要为您的案例获取正确的服务点对象,您必须执行此操作:
ServicePointManager.FindServicePoint(
new Uri("https://test.com"),
new WebProxy(new Uri("http://127.0.0.1:8888")))
.ConnectionLeaseTimeout = 1000; // 1 second
现在你会看到正确的结果。请注意,它并不完全符合您的预期。第一个请求将打开新连接。第二个请求将不打开新连接,即使已经过了5秒。相反,它会根据请求设置Connection: close
标头,表示应该关闭连接。然后,下一个请求(第三个)将最终启动新连接。就ConnectionLeaseTimeout
而言,这是预期的行为。