为什么C#HttpClient不能调用此URL(总是超时)?

问题描述 投票:2回答:2

我一直在开发一个确定网页信息的应用程序。其中一个组件涉及向URL发出HTTP GET请求,抓取HTML并对其进行分析。除了一个之外,我已经抛出了每个网址都可以正常运行...

罪魁祸首是.NET HttpClient似乎总是超时请求问题域中的任何URL。但是,浏览器请求的相同URL会在几毫秒内返回内容。没有任何关于标题似乎不寻常。

超时超时只会导致需要更长的时间才会被炸毁。我用同样的结果尝试了几分钟。我尝试了各种各样的东西,例如将用户代理字符串设置为Chrome的字符串,但无济于事。

有问题的域名是:http://careers.adidas-group.com注意同一站点也在https://careers.adidas-group.com上运行HTTPS(它有一个有效的证书)。使用任一协议都会导致相同的错误。

我可以用一个简单的C#控制台应用程序来显示问题,如下所示:

static void Main(string[] args)
{
    string url = "http://careers.adidas-group.com";

    var client = new HttpClient
    {
        Timeout = TimeSpan.FromSeconds(10)
    };

    using (var message = new HttpRequestMessage(HttpMethod.Get, url))
    {
        using (var httpResponse = Task.Run(() => client.SendAsync(message)).Result)
        {
            Console.WriteLine("{0}: {1}", httpResponse.StatusCode, httpResponse.ReasonPhrase);
        }
    }

    Console.ReadLine();
}

请注意,在上面的示例中,我将超时设置为10秒,只是为了加快问题 - 但是,增加超时没有任何区别。

具有不同URL的相同代码(例如https://stackoverflow.com/)运行正常。

另请注意,上面的代码已简化为作为控制台应用程序运行。我的实际代码在异步MVC控制器方法中异步运行(使用await) - 我只是使用Task.Run(() => )使其与示例中的同步Main方法的上下文一起使用。但它对结果没有任何影响。 (实际的例外是“任务被取消”,但似乎是超时的sympton,而不是实际问题)。

任何人都可以向我解释为什么会发生这种情况(这是关于服务器配置吗?)以及我可以做什么来使HttpClient满足请求?谢谢。

c# http asynchronous timeout dotnet-httpclient
2个回答
3
投票

好的,经过大量的调查后我决定必须要求服务器在请求中查找特定的头文件。所以我检查了大多数浏览器发送的内容,复制了这些内容,然后最终将其削减到需要以下所有标题的服务器:

client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate");
client.DefaultRequestHeaders.Add("Accept-Language", "en-GB,en;q=0.9,en-US;q=0.8");

删除其中任何一个,服务器将不响应。很奇怪!

感谢所有看过这个的人,我希望这个答案可以帮助将来的人:)

编辑 - 更奇怪

好吧,奇怪现在还在继续,因为即使这解决了本地运行的问题(在VS 2017中使用IIS Express),它在部署到实时环境(在IIS 7.5 / Windows Server中运行)时仍然无效。与控制台应用程序版本相同 - 适用于本地PC,不适用于服务器。尝试了3台Windows服务器,相同的代码,并且它在一台服务器上运行而在其他两台机器上运行。的bizzare。

进一步编辑 - 一个决议?

因此,在进一步阅读之后,看起来certain web-servers,例如akamai ghost(托管有问题的域)有一些相当复杂的“bot”检测,它拒绝来自未知客户端的连接。措施包括检查HTTP请求标头的顺序,以便它们与用户代理正常发送的顺序相匹配(即,如果您伪造用户代理字符串为Chrome,则最好像Chrome一样,在chrome命令中发送标头并接受相同的内容类型等)。

在尝试伪造大量浏览器用户代理字符串后,我最终发现“假装”是Google PageSpeed bot工作即。将user-agent字符串设置为:“Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko; Google Page Speed Insights) Chrome/27.0.1453 Safari/537.36

无论使用何种版本的Windows服务器或.NET Framework,这似乎都有效。

我最终提出的标题是:

this.Client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/apng,*/*;q=0.8");
this.Client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
this.Client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
this.Client.DefaultRequestHeaders.Add("Accept-Language", "en-GB,en;q=0.9,en-US;q=0.8");
this.Client.DefaultRequestHeaders.Add("Connection", "keep-alive");
this.Client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
this.Client.DefaultRequestHeaders.Add("Pragma", "no-cache");
this.Client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko; Google Page Speed Insights) Chrome/27.0.1453 Safari/537.36");

1
投票

你提出的答案是正确的。但是为了将来通知,我建议使用像Charles或Fiddler这样的Web调试器。它可以更轻松地复制您的请求,并最终找到您未收到主机响应的原因。在这个例子中,我使用了Charles。

WebRequest information

从我的Visual Studio Debugger中我可以看到客户端“DefaultHeaders”都是空的。所以现在OP已经证明我们需要做的就是将标题添加到我们的客户端并希望它满足主机。

static void Main(string[] args)
{
    string url = "http://careers.adidas-group.com";

    var client = new HttpClient
    {
        Timeout = TimeSpan.FromSeconds(10)
    };

    client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate");
    client.DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.5");
    client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0");
    client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");

    using (var message = new HttpRequestMessage(HttpMethod.Get, url))
    {

        using (var httpResponse = Task.Run(() => client.SendAsync(message)).Result)
        {
            Console.WriteLine("{0}: {1}", httpResponse.StatusCode, httpResponse.ReasonPhrase);
        }
    }

    Console.ReadLine();
}

我只是打扰添加我知道对大多数主机必不可少的东西。测试上面的代码我们得到一个代码'OK:OK'。如果我们尝试删除以下任何一行:

client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate");
client.DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.5");
client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");

我们将再次陷入无休止的循环中。这意味着主机不关心您正在使用的用户代理。 adidas的robots.txt(https://careers.adidas-group.com/robots.txt)也表明了这一点 - 这表明(因为数据挖掘者是不使用浏览器的自动化服务) - 阿迪达斯不介意在他们的域中拥有几个蜘蛛/数据挖掘者。

© www.soinside.com 2019 - 2024. All rights reserved.