PHP/Curl: HEAD Request занимает много времени на некоторых сайтах

У меня есть простой код, который выполняет запрос заголовка для URL-адреса, а затем печатает заголовки ответов. Я заметил, что на некоторых сайтах это может занять много времени.

Например, запрос http://www.arstechnica.com занимает около двух минут. Я пробовал тот же запрос с использованием другого веб-сайта, который выполняет ту же основную задачу, и он возвращается немедленно. Поэтому должно быть что-то, что я установил неправильно, что вызвало эту задержку.

Вот код, который у меня есть:

$ch = curl_init();
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt ($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);

// Only calling the head
curl_setopt($ch, CURLOPT_HEADER, true); // header will be at output
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'HEAD'); // HTTP request is 'HEAD'

$content = curl_exec ($ch);
curl_close ($ch);

Здесь ссылка на веб-сайт, который выполняет ту же функцию: http://www.seoconsultants.com/tools/headers.asp

Код выше, по крайней мере на моем сервере, занимает две минуты, чтобы получить www.arstechnica.com, но служба по ссылке выше вернет ее сразу.

Что мне не хватает?

Ответ 1

Попробуйте немного упростить его:

print htmlentities(file_get_contents("http://www.arstechnica.com"));

Вышеуказанные выходы мгновенно отображаются на моем веб-сервере. Если это не так, у вас есть хороший шанс, что ваш веб-хост имеет какую-то настройку для дросселирования этих запросов.

ИЗМЕНИТЬ

Так как это происходит мгновенно для вас, попробуйте установить эту настройку завивки на исходный код:

curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);

Используя инструмент, который вы опубликовали, я заметил, что http://www.arstechnica.com имеет 301 заголовок, отправленный для любого отправленного ему запроса. Возможно, что cURL получает это и не соответствует указанному ему новому местоположению, тем самым вызывая зависание script.

SECOND EDIT:

Любопытно, что попытка использовать тот же самый код, который у вас был выше, заставил мой веб-сервер повесить тоже. Я заменил этот код:

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'HEAD'); // HTTP request is 'HEAD'

При этом:

curl_setopt($ch, CURLOPT_NOBODY, true);

Каким образом руководство рекомендует выполнить запрос HEAD. Это заставило его работать мгновенно.

Ответ 2

Вы должны помнить, что HEAD - это всего лишь предложение для веб-сервера. Для HEAD, чтобы делать правильные вещи, это часто требует определенных явных усилий со стороны админов. Если вы HEAD статический файл Apache (или независимо от того, что ваш веб-сервер) будет часто шаг за шагом делать правильные вещи. Если вы НАЗАД динамическую страницу, по умолчанию для большинства настроек необходимо выполнить путь GET, собрать все результаты и просто отправить обратно заголовки без содержимого. Если это приложение находится в настройке уровня 3 (или более), этот вызов потенциально может быть очень дорогим и ненужным для контекста HEAD. Например, на сервлете Java по умолчанию doHead() просто вызывает doGet(). Чтобы сделать что-то более разумное для приложения, разработчику пришлось бы явно реализовать doHead() (и чаще всего этого не будет).

Я столкнулся с приложением из компании, состоящей из 100 компаний, которая используется для загрузки нескольких сотен мегабайт информации о ценах. Мы проверяем наличие обновлений этих данных, выполняя запросы HEAD достаточно регулярно, пока измененная дата не изменится. Оказалось, что этот запрос фактически сделает обратные вызовы, чтобы генерировать этот список каждый раз, когда мы делали запрос, который включал гигабайты данных на их задней стороне и xfer между несколькими внутренними серверами. Они были не очень счастливы с нами, но как только мы объяснили пример использования, они быстро придумали альтернативное решение. Если бы они внедрили HEAD, а не полагались на свой веб-сервер, чтобы подделать его, это не было бы проблемой.

Ответ 3

Я использовал функцию ниже, чтобы узнать перенаправленный URL.

$head = get_headers($url, 1);

Второй аргумент заставляет его возвращать массив с ключами. Напр. ниже будет указано значение Location.

$head["Location"]

http://php.net/manual/en/function.get-headers.php

Ответ 4

Если моя память не сработает, я делаю запрос HEAD в CURL, меняет версию протокола HTTP на 1.0 (которая медленная и, вероятно, виноватая часть здесь), попробуйте изменить ее на:

$ch = curl_init();
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt ($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);

// Only calling the head
curl_setopt($ch, CURLOPT_HEADER, true); // header will be at output
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'HEAD'); // HTTP request is 'HEAD'
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); // ADD THIS

$content = curl_exec ($ch);
curl_close ($ch);

Ответ 5

Это:

curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);

Я не пытался получить заголовки.
Я просто пытался сделать загрузку страницы некоторыми данными не займет 2 минуты, как описано выше.
Этот волшебный маленький вариант снизил его до 2 секунд.