Почему C # HttpClient не может вызывать этот URL-адрес (всегда истекает время ожидания)?

Я разрабатываю приложение, которое определяет информацию о веб-страницах. Один из компонентов этого заключается в отправке HTTP-запроса GET на URL-адрес, захвате HTML и его анализе. Это отлично работало со всеми URL-адресами, которые я ему указывал, кроме одного ...

Виновником является .NET HttpClient, который всегда, кажется, теряет время ожидания при запросе любого URL-адреса в проблемной области. Однако тот же URL-адрес, запрошенный браузером, возвращает контент в течение миллисекунд. В заголовках нет ничего необычного.

Увеличение тайм-аута просто приводит к тому, что бомбометание занимает больше времени. Я пробовал минуты с тем же результатом. Я пробовал разные вещи, например, настраивал строку User Agent на строку Chrome, но безрезультатно.

Рассматриваемый домен: http://careers.adidas-group.com Обратите внимание на этот же сайт работает по HTTPS по адресу https://careers.adidas-group.com (имеет действующий сертификат) . Использование любого протокола приводит к одной и той же ошибке.

Я могу показать проблему с помощью простого консольного приложения 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/) работает нормально.

Также обратите внимание, что приведенный выше код упрощен для запуска в качестве консольного приложения. Мой фактический код выполняется правильно асинхронно (с использованием await) в методе async MVC-контроллера - я просто использую Task.Run(() => ), чтобы заставить его работать с контекстом синхронного метода Main в примере. Но для результата это не имеет значения. (Фактическое исключение - «Задача была отменена», но это скорее симптом тайм-аута, а не реальная проблема).

Может ли кто-нибудь объяснить мне, почему это происходит (это связано с конфигурацией сервера?) И что, если что-то еще, я могу сделать, чтобы HttpClient выполнил запрос? Спасибо.


person Dan Diplo    schedule 14.02.2018    source источник
comment
Может быть, это заголовки агента пользователя?   -  person maccettura    schedule 14.02.2018
comment
Также бывает с инструментом тестирования сайта: https://redbot.org/?uri=http%3A%2F%2Fcareers.adidas-group.com%2F   -  person Julian Reschke    schedule 14.02.2018
comment
@JulianReschke Нет, не видел, но интересно, что та же проблема с тайм-аутом возникает при использовании этого инструмента. Сервер должен отклонять ботов, но я не понимаю, по каким критериям.   -  person Dan Diplo    schedule 14.02.2018
comment
Тот же результат с curl   -  person Max    schedule 14.02.2018
comment
@maccettura Это была одна из моих первых мыслей, но я попытался установить строку user-agent в запросе к некоторым популярным агентам браузера, но это не имело никакого значения.   -  person Dan Diplo    schedule 14.02.2018


Ответы (2)


Хорошо, после долгого расследования я решил, что это должно быть сервером, который ищет определенные заголовки в запросе. Поэтому я проверил, что отправляет большинство браузеров, скопировал их и, наконец, сократил это до сервера, требующего наличия всех следующих заголовков:

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). То же самое с версией консольного приложения - работает на локальном ПК, не работает на сервере. Пробовал 3 сервера Windows, тот же код, и он работал на одном, а не на двух других. Bizzare.

Дальнейшее редактирование - разрешение?

Поэтому после дальнейшего чтения появляются определенные веб-серверы, такие как akamai ghost (на котором размещен рассматриваемый домен), имеют довольно сложное обнаружение «ботов», которое отклоняет соединения от неизвестных клиентов. Меры включают проверку порядка заголовков 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 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");
person Dan Diplo    schedule 14.02.2018
comment
@Evk Да, вы правы - это не было одним из обязательных. Отредактирую свой ответ. - person Dan Diplo; 14.02.2018

Вы пришли к правильному ответу. Однако на будущее я рекомендую использовать веб-отладчик, например Charles или Fiddler. Это упрощает репликацию ваших запросов и окончательное выяснение причины, по которой вы не получаете ответа от хоста. В этом примере я использовал Charles.

Информация о веб-запросе

Из моего отладчика Visual Studio я мог видеть, что все клиенты 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();
}

Я только озаботился добавлением тех, которые, как я знал, необходимы большинству хостов. Проверяя приведенный выше код, мы получаем код «ОК: ОК». Если мы попытаемся удалить любую из этих строк:

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 adidas (https://careers.adidas-group.com/robots.txt), что предполагает (поскольку майнеры данных - это автоматизированные службы, не использующие браузер), что Adidas не возражает против наличия пары пауков / майнеров данных вокруг своих домен.

person Kent Kostelac    schedule 05.03.2018
comment
Спасибо за ваш вклад. Я пытался использовать Fiddler, но в моей рабочей сети возникли проблемы. Я не слышал о Чарльзе, так что проверю. Ваше здоровье! - person Dan Diplo; 06.03.2018
comment
Я наблюдал такое же поведение. Добавление подтверждения того, что здесь написал Кент. - person Sharath; 20.11.2020