Intereting Posts

Отправлять 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, поэтому не делайте этого.

    Короче: все ответы могут быть отброшены.

Идеи для решений:

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

  • Я нашел php-ga , пакет для создания серверной Google Analytics с PHP. На странице проекта упоминается: «Можно настроить на […] использование неблокирующих запросов». До сих пор я не нашел времени для изучения того, какой метод php-ga использует внутри, но этот метод может быть таким!

Вкратце: что является лучшим решением для создания общего отслеживания / аналитики на стороне сервера с PHP.

К сожалению, PHP по определению блокирует . Хотя это справедливо для большинства функций и операций, которые вы обычно обрабатываете, текущий сценарий отличается.

Процесс, который мне нравится называть HTTP-Ping , требует, чтобы вы касались только определенного URI, заставляя конкретный сервер загружаться, это внутренняя логика. Некоторые функции позволяют достичь чего-то очень похожего на этот HTTP-пинг , не дожидаясь ответа.

Обратите внимание, что процесс пинга URL-адреса является двухэтапным процессом:

  1. Решить DNS
  2. Выполнение запроса

Хотя запрос должен быть довольно быстрым после того, как DNS будет разрешен и будет установлено соединение, не так много способов сделать DNS-разрешение быстрее.

Некоторые способы выполнения http-ping:

  1. cURL , установив CONNECTION_TIMEOUT на низкое значение
  2. fsockopen , закрывшись сразу после написания
  3. stream_socket_client (то же, что и fsockopen), а также добавляет STREAM_CLIENT_ASYNC_CONNECT

Хотя оба cURL и fsockopen блокируются при разрешении DNS. Я заметил, что fsockopen значительно быстрее, даже в самых худших сценариях.

stream_socket_client с другой стороны, должен исправить проблему разрешения DNS и должен быть оптимальным решением в этом сценарии, но мне не удалось заставить его работать.

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

Системные вызовы чаще всего блокируются, а по умолчанию pcntl не включен.

Я бы назвал tracker.example.com следующим образом:

 get_headers('http://tracker.example.com?product_number=5230&price=123.52'); 

и в сценарии трекера:

 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; 

Я реализовал функцию быстрого запроса 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); } 

Вы можете использовать shell_exec и curl командной строки.

Например, см. Этот вопрос

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

 <?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); ?> 

Вы можете сделать это, используя CURL напрямую.

Я выполнил его с использованием очень короткого таймаута ( CURLOPT_TIMEOUT_MS ) и / или с помощью curl_multi_exec .

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