连接到VPN时HttpClient.GetAsync超时

时间:2018-09-22 00:29:49

标签: c# windows vpn dotnet-httpclient

当系统未使用VPN时,C#4.5.2框架HttpClient.GetAsync()方法在Windows 10上可以正常工作。

连接VPN后,对同一地址的HttpClient.GetAsync()调用只会阻塞,直到超时为止。 Edge和Chrome都可以访问该地址。

是否有办法查看正在发生的事情? HttpClient有何不同之处?

更新:致电python3得到了一些有趣的线索。没有VPN 此调用仅返回所有可以连接的IPv4地址。连接了VPN客户端后,Dns.GetHostEntry()返回了列表顶部的其他IPv6地址。与所有IPv6地址的连接超时,但所有IPv4地址仍然可以正常工作。现在有一种方法可以找出而不尝试连接哪些地址有效而哪些地址无效的方法吗?

2 个答案:

答案 0 :(得分:0)

以我的经验,这听起来像VPN /防火墙问题。在Windows中切换的一项快速操作是在VPN适配器属性下,尝试取消选中“在远程网络上使用默认网关”-我知道这听起来像是一个长镜头,但过去曾遇到过此问题... enter image description here

答案 1 :(得分:0)

我必须自己回答这个问题,因为这个问题的原因很简单,但症状却很混乱。

根本原因:

当系统未连接到VPN时,DNS仅报告主机的IPv4地址。所有IPv4地址都可以使用。

VPN连接处于活动状态时,DNS会返回除IPv4之外的IPv6地址。 IPv4地址仍可访问,但IPv6无法访问。

这种无效的网络配置的原因仍然是一个谜,值得单独发表。

令人困惑的部分:

某些应用程序无论处于何种VPN连接状态都可以正常工作。

“但是Web浏览器可以通过或不通过VPN连接到同一主机。”真正。浏览器可能会使用Happy eyeballs方法尝试同时使用IPv4和IPv6进行连接。

“但是我的旧应用程序没有连接问题。”也是如此。默认情况下,一些较旧但不是较旧的应用程序使用IPv4协议。必须明确实现对IPv6或IPv4 + IPv6的支持。

“但有时可以工作”。 VPN连接不可靠时会发生这种情况。它导致各种解决方案,这仅仅是巧合。

正在发生的事情

HttpClient.GetAsync()使用默认的DNS解析,并且可以使用IPv4和IPv6地址进行连接。它没有区别,也没有直接的方法来影响协议的选择。如果DNS返回无法访问的地址,则HttpClient可能会使用该无效地址进行连接,从而导致超时。

可能的解决方法:

最好:请IT部门解决IPv6 DNS问题。 DNS不应报告无法访问的地址。

好:实施Happy eyeballs方法。使用数字IP而不是使用主机名自动解析来连接到IPv6和IPv4主机地址。

确定:始终使用数字IP连接到IPv4。

以下是显示如何连接到特定IP地址的代码:

// Get DNS entries for the host.
var hostEntry = Dns.GetHostEntry(uri.Host); 

// Get IPv4 address
var ip4 = hostEntry.AddressList.First(addr => addr.AddressFamily == AddressFamily.InterNetwork);
// Build URI with numeric IPv4
var uriBuilderIP4 = new UriBuilder(uri); 
uriBuilderIP4.Host = ip4.ToString()); 
var uri4 = uriBuilder4.Uri; 

// Get IPv6 address
var ip6 = hostEntry.AddressList.First(addr => addr.AddressFamily == AddressFamily.InterNetworkV6);

// Build URI with numeric IPv6
var uriBuilderIP6 = new UriBuilder(uri); 
uriBuilderIP6.Host = $"[{ip6}]"; 
var uri6 = uriBuilder6.Uri; 

对于HTTPS连接,数字地址只能与带有主机名(而不是IP地址)的“ host”标头一起使用。这是添加它的方法。

var client = new HttpClient(); 
// Add "host" header with real host name e.g. stackoverflow.com 
client.DefaultRequestHeaders.Add("Host", uri.Host);