其他分享
首页 > 其他分享> > HttpClient-不接受DNS更改

HttpClient-不接受DNS更改

作者:互联网

我已经阅读了几篇文章,以及使用静态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);
            }
        });

当我在提琴手中查看流量时:

enter image description here

行为符合预期.当请求和响应完成时,每个create和dispose都会强制建立一个连接.

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();
    }

我期望与上一张图片具有相同的行为,但是它看起来像下面的样子:

enter image description here

如果我再添加HttpClient.DefaultRequestHeaders.ConnectionClose = true;我得到了期望的结果,但是这是我们要避免的-为每个请求响应创建一个连接.

那么我在Fiddler中期望的结果正确吗?还是通过设置ConnectionLeaseTimeout和/或DnsRefreshTimeout缺少某些东西?我真的很想测试此行为,并确保在ServicePointManager上设置这些属性可以解决HttpClient静态实例的已知DNS问题.

解决方法:

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的了解而言,这是预期的行为.

标签:testing,dotnet-httpclient,c
来源: https://codeday.me/bug/20191110/2014750.html