连接VPN时,HttpClient.GetAsync超时

4
C# 4.5.2 框架的 HttpClient.GetAsync() 方法在 Windows 10 系统未使用 VPN 时可以正常工作。但当连接 VPN 后,对相同地址的 HttpClient.GetAsync() 调用会一直阻塞直到超时。Edge 和 Chrome 都没有访问该地址的问题。是否有办法查看发生了什么?HttpClient 做了哪些不同之处?
更新:通过调用 Dns.GetHostEntry() 得到了一些有趣的线索。如果没有 VPN,此调用仅返回可连接的 IPv4 地址。与 VPN 客户端连接后,Dns.GetHostEntry() 返回顶部的其他 IPv6 地址。所有 IPv6 地址的连接都超时了,但所有 IPv4 的连接仍然正常工作。现在是否有一种方法可以在尝试连接之前找出哪些地址有效,哪些无效?

这意味着当您连接到VPN时,API无法连接。这不是HttpClient的问题,而是网络阻止了对API的流量。 - Chetan
但是我可以从Edge和Chrome连接。它们有什么不同? - Optional Option
命令行。当前用户。 - Optional Option
Ping无法连接到任何地址。通过IP连接适用于IPv4,但不适用于IPv6。 - Optional Option
也许有一些代理设置,Chrome可以处理连接,但是HttpClient.GetAsync()需要额外的代码。请查看此链接:https://dev59.com/ZF0a5IYBdhLWcg3w3L8- - cahit beyaz
显示剩余4条评论
2个回答

1

作为这个问题的根本原因,当系统未连接到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连接,只有在“host”头中带有主机名(而非IP地址)时,数字地址才起作用。以下是添加它的方法。

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

谢谢,这个答案对我帮助很大。不知道为什么在使用WebClient时,即使是HTTP连接,我仍然需要设置一个“Host”头。 - ChrisUK

1
据我的经验,这听起来像是VPN /防火墙问题。Windows 中一个快速切换的方法是在 VPN 适配器属性下,尝试取消选中“使用远程网络上的默认网关” - 我知道这听起来很冒险,但我过去遇到过这个问题... 在此输入图片描述

我的电脑上没有那个设置。整个IP设置选项卡看起来都不一样。 - Optional Option

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接