首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么C# HttpClient不能调用这个URL (总是超时)?

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

Stack Overflow用户
提问于 2018-02-14 15:13:59
回答 2查看 7.5K关注 0票数 4

我一直在开发一个确定网页信息的应用程序。其中一个组件涉及向URL发出HTTP请求,获取HTML并对其进行分析。我抛给它的每个URL都很好,除了一个.

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

增加超时只会导致爆炸需要更长的时间。我试过几分钟也有同样的结果。我尝试过各种方法,比如将用户代理字符串设置为Chrome,但没有效果。

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

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

代码语言:javascript
运行
复制
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控制器方法中异步运行(使用等待)--我只是使用Task.Run(() => )使它在示例中与同步主方法的上下文一起工作。但这对结果没有任何影响。(实际的例外是“任务被取消”,但这似乎是对超时的同情,而不是实际的问题)。

有人能向我解释一下为什么会发生这种情况(是关于服务器配置的吗?)如果有的话,我能做些什么来让HttpClient满足这个请求呢?谢谢。

EN

回答 2

Stack Overflow用户

发布于 2018-02-14 16:22:27

好的,经过大量的调查,我决定一定是服务器在请求中寻找特定的头。因此,我检查了大多数浏览器发送的内容,复制了这些内容,最后将其压缩到服务器上,要求出现以下所有标题:

代码语言:javascript
运行
复制
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服务器,相同的代码,它工作在一个,而不是在其他两个。比扎雷。

进一步编辑-一个决议?

因此,在进一步阅读后,它似乎出现了某些web服务器,例如akamai幽灵(它承载了所讨论的域)有一些相当复杂的"bot“检测,它拒绝来自未知客户端的连接。措施包括检查HTTP请求头的顺序,以便它们与用户代理通常发送的内容相匹配(即。如果您伪造用户代理字符串为Chrome,您最好的行为与Chrome完全一样,按照chrome的顺序发送标头,并接受相同的内容类型等等)。

在尝试过伪造大量浏览器用户代理字符串之后,我最终发现“假装”是Google PageSpeed机器人的效果很好。将用户代理字符串设置为:"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框架,这似乎都是有效的。

我最终想出的标题是:

代码语言:javascript
运行
复制
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");
票数 7
EN

Stack Overflow用户

发布于 2018-03-05 14:28:21

你想出的答案是正确的。但是,为了以后的注意,我建议使用像Charles或Fiddler这样的web调试器。它使复制请求变得更容易,并最终找到为什么您没有从主机获得任何响应的根本原因。在这个例子中,我使用了Charles。

从我的中,我可以看到客户机"DefaultHeaders“都是空的。因此,正如OP已经展示的那样,我们所需要做的就是将头添加到我们的客户端,并希望它满足主机的需求。

代码语言:javascript
运行
复制
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‘。如果我们试图删除这些行中的任何一行:

代码语言:javascript
运行
复制
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");

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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48790438

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档