Подтвердить что ты не робот

Отправлять 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.

4b9b3361

Ответ 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);
?>