连接到 *** 时 HttpClient.GetAsync 超时
Posted
技术标签:
【中文标题】连接到 *** 时 HttpClient.GetAsync 超时【英文标题】:HttpClient.GetAsync times out when connected to *** 【发布时间】:2019-02-26 09:05:28 【问题描述】:当系统不使用 *** 时,C# 4.5.2 框架 HttpClient.GetAsync() 方法在 Windows 10 上运行良好。
当 *** 连接时,对同一地址的 HttpClient.GetAsync() 调用只会阻塞,直到超时。 Edge 和 Chrome 访问同一个地址都没有问题。
有没有办法查看正在发生的事情? HttpClient 有什么不同?
更新:拨打Dns.GetHostEntry()
得到了一些有趣的线索。没有***
此调用仅返回所有都可以连接到的 IPv4 地址。连接 *** 客户端后,Dns.GetHostEntry()
在列表顶部返回了额外的 IPv6 地址。与所有 IPv6 地址的连接都已超时,但所有 IPv4 地址仍然可以正常工作。现在有没有办法在不尝试连接哪些地址有效而哪些地址无效的情况下找出答案?
【问题讨论】:
这意味着当您连接到 *** 时,API 无法连接。它不是 HttpClient,而是阻止 API 流量的网络 是的。使用 Fiddler,确保发出某种请求。 但我可以从 Edge 和 Chrome 连接。它们有何不同? 什么样的程序在调用GetAsync()
?它是桌面应用程序、服务、Web 服务器等吗?它以什么用户身份运行——你的?
命令行。当前用户。
【参考方案1】:
根据我的经验,这听起来像是 *** / 防火墙问题。在 Windows 中切换的一项快速操作是在您的 *** 适配器属性下,尝试取消选中“在远程网络上使用默认网关” - 我知道这听起来很遥远,但过去曾遇到过这个问题......
【讨论】:
我的电脑上没有该设置。整个 IP 设置选项卡看起来不同。【参考方案2】:必须自己回答这个问题,因为这个问题的原因很简单,但症状很混乱。
根本原因:
当系统未连接到 *** 时,DNS 仅报告主机的 IPv4 地址。所有 IPv4 地址均可用。
当 *** 连接处于活动状态时,除了 IPv4 之外,DNS 还会返回 IPv6 地址。 IPv4 地址仍可访问,但 IPv6 不可访问。
这种无效网络配置的原因仍然是一个谜,值得单独发布。
令人困惑的部分:
无论 *** 连接状态如何,某些应用程序都能正常工作。
“但无论是否使用 ***,网络浏览器都可以连接到同一台主机。”真的。浏览器可能会使用Happy eyeballs 方法尝试同时使用 IPv4 和 IPv6 进行连接。
“但是我的旧应用程序连接没有问题。”也是真的。默认情况下,一些较旧且不太旧的应用程序使用 IPv4 协议。必须明确实现对 IPv6 或 IPv4+IPv6 的支持。
“但它有时会起作用”。当 *** 连接不可靠时会发生这种情况。它导致各种巧合的解决方案。
到底发生了什么:
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 地址)的“主机”标头。这是添加它的方法。
var client = new HttpClient();
// Add "host" header with real host name e.g. ***.com
client.DefaultRequestHeaders.Add("Host", uri.Host);
【讨论】:
谢谢,这个答案对我帮助很大。知道为什么我在使用 WebClient 时仍需要设置“主机”标头 - 即使使用 HTTP 连接?以上是关于连接到 *** 时 HttpClient.GetAsync 超时的主要内容,如果未能解决你的问题,请参考以下文章
连接到 postgresql:dbserver db 通过 JDBC 连接到 Databricks 时连接被拒绝
将 nesjs 应用程序连接到 SQL Server Express 时出错:无法连接到 localhost:1433 - 自签名证书