为什么这个HTTPS WebRequest在浏览器中可以工作,但却超时了?

20

以下是我的请求:

var request = (HttpWebRequest) WebRequest.Create("https://mtgox.com/");
request.CookieContainer = new CookieContainer();
request.AllowAutoRedirect = false;
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
request.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";
request.Headers[HttpRequestHeader.AcceptLanguage] = "en-gb,en;q=0.5";
request.Headers[HttpRequestHeader.AcceptCharset] = "ISO-8859-1,utf-8;q=0.7,*;q=0.7";
request.Timeout = 5000;
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0";
request.Method = "GET";

request.GetResponse();

这些头信息是使用 HttpFox 从 Firefox 复制的。 我使用 Fiddler2 验证了至少在 HTTP 请求方面,Firefox 请求和我的请求之间的头信息完全相同。

然而,在使用 HTTPS 请求此特定网站时,请求会超时。 它适用于其他网站。

我肯定是与 Firefox 使用不同的方法进行请求,因为它总是在 Firefox 中工作。 但是,我无法使用 Fiddler2 进行调试,因为每当 Fiddler2 转发这些请求时,即使是由 Firefox 发起的请求,它们也会超时。

这只是一个非常有问题的网站吗? 上述哪一部分表明了我并不是 Firefox?

6个回答

43

使用 Microsoft Network Monitor,我发现 HttpWebRequest 在发送客户端密钥交换时会卡住,它根本没有像应该的那样发送。服务器在等待它,但它从未到达。

解决方法是强制让 HttpWebRequest 使用 SSL3 而不是 TLS(即使 TLS 应该自动转换为 SSL3):

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

我想我永远不会知道这是为什么 - 只是其中一个那些神秘的东西,需要花费比我认识的任何人都更多的时间才能弄清楚...

关于捕获的一件事情与众不同:TLS变体在Server Hello响应中有一个“Alert”条目,而在SSL3交换以及所有实际工作的TLS交换中都不存在。有趣的是,在Firefox成功执行请求的捕获中也存在相同的警报。

最后,似乎在我最初发布此问题时出现了临时的OCSP故障,后来已经解决。这加剧了混乱,但不是核心问题。


1
@enverpex - 你这个了不起的家伙!!!我已经过去几个小时一直在痛苦地尝试弄清楚为什么我的 HttpWebRequest 在特定网站上会出现停滞的情况,我尝试了所有的头信息,但只有这段代码有效,谢谢!!!A++++++ - Dalbir Singh
上帝保佑您,先生!当我对同一服务器进行两次调用时,就会发生这种情况。第二个调用由于未知原因而挂起,直到我进行了这个更改。 - koopaking3
这对我没有起作用。我不得不将SecurityProtocol设置为SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls(请参见下面的答案)。 - henon
1
如何在本问题中使用Microsoft Network Monitor - Kiquenet

12

HttpWebRequest/HttpWebResponse调用出现超时错误的典型原因是"未关闭响应对象/流",这会使连接保持活动状态。在读取流内容后,您只需关闭Stream对象或HttpWebResponse对象即可。默认连接限制为2。

HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
Stream stream = webResponse.GetResponseStream();
string responseString = ((TextReader)new StreamReader(stream)).ReadToEnd();
webResponse.Close();

如果您的逻辑是在一个将被许多用户同时调用的 Web 服务中实现的,那么您可能希望考虑增加 HttpWebRequest 对象中的连接限制。

HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);    
webRequest.ServicePoint.ConnectionLimit = 20;

我来这里是为了 http://(不是 https://)和不要 .close() 我的连接似乎是问题,即在代码中没有工作。页面总是可以在浏览器中加载。 - bendecko
1
那解决了我的问题。在使用完成后关闭流是合乎逻辑的,类似于.dispose()。很好的解释,谢谢。此外,文档在备注部分也说了同样的话:docs.microsoft HttpWebResponse - mihkov

9
在Windows 7上,.NET框架实现了一种TLS扩展:服务器名称指示(RFC4366)。根据您的帖子What does this TLS Alert mean,服务器响应“未知名称”。不确定为什么会报告连接超时,因为它实际上并没有。您的网络跟踪应该显示在此[FN,ACK]之后客户端启动连接终止。降级到SSL3可以避免调用SNI。
另外,请注意,在Windows XP上,相同的.NET框架不使用TLS服务器名称指示扩展。您的程序将在那里运行...
在我的情况下,我追踪到这是由于Apache缺少ServerName指令导致的。在SSL配置中添加ServerName解决了这个问题,因为现在Web服务器不再不知道自己的名称。

您也可以在Java 7中关闭SNI的发送:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7127374 - eckes

4

我遇到了与https请求相同的超时问题,但是所有的答案都没有帮助到我。刚刚我找到了一个解决方案,成功地解决了我的问题。请注意,这仅适用于 .net framework 4.5 或更高版本。

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
var response = WebRequest.Create("https://yoursecurewebservice").GetResponse();
var body = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.WriteLine(body);

4

最近发现了这个同样的问题,想看看微软是否已经在更新的 .net 版本中修复了这个问题。这是我测试的代码(为保护隐私,域名已删除):

HttpWebRequest request =
    (HttpWebRequest)WebRequest.Create("https://www.xxSomeDomainNamexx.com/");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
Console.WriteLine(reader.ReadToEnd());

我将这个代码编译成了2.0、3.0和3.5版本的.Net,发现所有的表现都与大家讨论的一样。然后我尝试编译成4.0和4.5版本,在两个地方都得到了正确的响应。

基于此,看起来微软可能已经在更新的.Net版本中解决了这个问题。为了记录下来,我还测试了enverpex建议的SecurityProtocol更改,并在2.0、3.0和3.5版本上成功实现。


2
最有可能的情况是HTTPS客户端无法验证服务器呈现的证书链,例如由于缺少根证书或不可访问的OCSP响应者。即,在浏览器和您使用的HTTPS客户端中配置可能存在差异。
作为其中一个选项,您可以使用我们的HTTPBlackbox组件的试用版,并尝试使用TElHTTPSClient进行连接。它将提供详细的错误信息(在出错的情况下),因此您将能够确定HttpWebRequest出了什么问题。

嗯,在使用Fiddler2连接Google的HTTPS时,会出现关于无效证书的异常,而不仅仅是挂起/超时... - enverpex
@enverpex 我会选择OCSP或CRL检查 - 它们需要额外的HTTP(S)连接,可能会超时。但这是你需要自己调试的问题 - 我们只能在这里猜测。 - Eugene Mayevski 'Callback
使用您的HTTPBlackbox\HTTPGet示例进行HTTPS/mtgox.com/443时,会出现相同的问题:“连接失败”。您说应该有详细的错误信息可用,但我在异常对象中找不到其他信息。您能提示我在哪里查找吗? - enverpex
@enverpex 这意味着无法连接到该网站。很可能是某个防火墙允许浏览器通过,但阻止了您的应用程序。另外,如果您处理 OnError 事件,则可能会提供更多信息。 - Eugene Mayevski 'Callback
使用OnError,结果发现这是一个证书验证问题。TElHTTPSClient抛出的异常确实也可以提到错误代码。我猜想,就像你所说的那样,.NET或者你的代码无法验证StartCom证书,但是Firefox和Chrome可以。甚至“https://www.startcom.org”本身在HTTPBlackbox中也会导致“连接失败”。 - enverpex
显示剩余2条评论

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