HttpClient-不支持对DNS的更改

HttpClient - DNS changes are NOT honoured(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);
            }
        });

当我在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问题。

推荐答案

将自身注册为代理。默认情况下,它监听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的预期行为。

这篇关于HttpClient-不支持对DNS的更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:HttpClient-不支持对DNS的更改