Отправлять HTTP-запрос с PHP без ожидания ответа?
Я хочу получить HTTP-запрос GET, отправленный с PHP. Пример:
http://tracker.example.com?product_number=5230&price=123.52
Идея состоит в том, чтобы сделать веб-аналитику на стороне сервера: вместо отправки отслеживания
информация с JavaScript на сервер, сервер отправляет отслеживание
информацию непосредственно на другой сервер.
Требования:
-
Запрос должен занять как можно меньше времени, чтобы не
заметно замедлить обработку страницы PHP.
-
Ответ от tracker.example.com
не должен быть
проверено. В качестве примеров можно привести некоторые возможные ответы
tracker.example.com
:
-
200: Это прекрасно, но не нужно проверять это.
-
404: Не повезло, но - снова - нет необходимости проверять это.
-
301: хотя перенаправление было бы уместным, оно задерживало бы
обработка страницы PHP, поэтому не делайте этого.
Вкратце: все ответы могут быть отброшены.
Идеи для решений:
-
В удаленном ответе кто-то предложил позвонить в командную строку
curl из PHP в процессе оболочки. Это кажется хорошей идеей,
только то, что я не знаю, если бы на
тяжелая нагрузка - это мудрое дело.
-
Я нашел php-ga, пакет для работы с сервером Google
Аналитика с PHP. На странице проекта это
"Можно настроить на [...] использование неблокирующих запросов".
До сих пор я не нашел времени для изучения того, какой метод php-ga
использует внутренне, но этот метод может быть этим!
В двух словах: что является лучшим решением для создания общих серверных
отслеживание/аналитика с PHP.
Ответы
Ответ 1
К сожалению, PHP по определению является блокировкой. Хотя это справедливо для большинства функций и операций, которые вы обычно обрабатываете, текущий сценарий отличается.
Процесс, который мне нравится называть HTTP-Ping, требует, чтобы вы касались только определенного URI, заставляя конкретный сервер загружать внутреннюю логику. Некоторые функции позволяют достичь чего-то очень похожего на этот HTTP-пинг, не дожидаясь ответа.
Обратите внимание, что процесс пинга URL-адреса является двухэтапным процессом:
- Разрешить DNS
- Выполнение запроса
При выполнении запроса достаточно быстро, как только DNS будет разрешен и будет установлено соединение, не так много способов сделать DNS-разрешение быстрее.
Некоторые способы выполнения http-ping:
- cURL, установив CONNECTION_TIMEOUT на низкое значение
- fsockopen, закрывшись сразу после записи
- stream_socket_client (так же, как fsockopen), а также добавление
STREAM_CLIENT_ASYNC_CONNECT
Пока оба cURL
и fsockopen
блокируются, пока DNS решается. Я заметил, что fsockopen значительно быстрее, даже в самых худших сценариях.
stream_socket_client
, с другой стороны, должен исправить проблему разрешения DNS и должен быть оптимальным решением в этом сценарии, но мне не удалось заставить его работать.
Одним из окончательных решений является запуск другого потока/процесса, который сделает это за вас. Выполнение системного вызова для этого должно работать, но также forking текущий процесс также должен это сделать. К сожалению, обе версии не очень безопасны в приложениях, где вы не можете контролировать среду, на которой работает PHP.
Системные вызовы чаще всего блокируются, а по умолчанию pcntl не включен.
Ответ 2
Я бы назвал tracker.example.com следующим образом:
get_headers('http://tracker.example.com?product_number=5230&price=123.52');
и в трекере script:
ob_end_clean();
ignore_user_abort(true);
ob_start();
header("Connection: close");
header("Content-Length: " . ob_get_length());
ob_end_flush();
flush();
// from here the response has been sent. you can now wait as long as you want and do some tracking stuff
sleep(5); //wait 5 seconds
do_some_stuff();
exit;
Ответ 3
Я реализовал функцию для быстрого запроса GET для URL-адреса, не дожидаясь ответа:
function fast_request($url)
{
$parts=parse_url($url);
$fp = fsockopen($parts['host'],isset($parts['port'])?$parts['port']:80,$errno, $errstr, 30);
$out = "GET ".$parts['path']." HTTP/1.1\r\n";
$out.= "Host: ".$parts['host']."\r\n";
$out.= "Content-Length: 0"."\r\n";
$out.= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
fclose($fp);
}
Ответ 4
Вы можете использовать shell_exec и curl командной строки.
В качестве примера см. этот вопрос
Ответ 5
Пришел сюда, исследуя аналогичную проблему. Если у вас есть соединение с базой данных, еще одна возможность - быстро направить данные запроса в таблицу, а затем выполнить отдельный процесс на основе cron, который периодически сканирует эту таблицу для обработки новых записей и делает запрос отслеживания, освобождая ваше веб-приложение должно выполнить сам запрос HTTP.
Ответ 6
Вы можете сделать это с помощью CURL
напрямую.
Я выполнил его с использованием очень короткого таймаута (CURLOPT_TIMEOUT_MS
) и/или используя curl_multi_exec
.
Будьте внимательны: в конце концов я прекратил этот метод, потому что не каждый запрос был правильно сделан. Это могло быть вызвано моим собственным сервером, хотя я не смог исключить возможность зависания лома.
Ответ 7
<?php
// Create a stream
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en"
)
);
$context = stream_context_create($opts);
// Open the file using the HTTP headers set above
$file = file_get_contents('http://tracker.example.com?product_number=5230&price=123.52', false, $context);
?>