从PHP发送HTTP请求而不等待响应?

时间:2013-01-16 13:48:53

标签: php http curl server-side web-analytics

我希望从PHP发送HTTP GET请求。例如:

http://tracker.example.com?product_number=5230&price=123.52

我们的想法是进行服务器端网络分析:而不是发送跟踪 从JavaScript到服务器的信息,服务器发送跟踪 信息直接发送到另一台服务器。

要求:

  • 请求应尽可能少花时间,以便不这样做 显着延迟处理PHP页面。

  • tracker.example.com的回复不需要 检查。作为例子,一些可能的回应来自 tracker.example.com

    • 200:没关系,但不需要检查。

    • 404:运气不好,但是 - 再次 - 无需检查。

    • 301:虽然重定向是合适的,但会延迟 处理PHP页面,所以不要这样做。

    简而言之:所有响应都可以被丢弃。

解决方案的想法:

  • 在一个现已删除的答案中,有人建议调用命令行 来自PHP的curl在shell进程中。这似乎是一个好主意, 只是我不知道是否分配了很多shell进程 重负荷是明智之举。

  • 我找到了php-ga,这是一个用于服务器端Google的软件包 来自PHP的分析。在项目的页面上,它是 提到:“可以配置为[...]使用非阻塞请求。” 到目前为止,我还没有时间去研究php-ga的方法 在内部使用,但这种方法可以是它!

简而言之:做通用服务器端的最佳解决方案是什么 来自PHP的跟踪/分析。

10 个答案:

答案 0 :(得分:29)

不幸的是,PHP的定义是阻止。虽然这适用于您通常会处理的大多数功能和操作,但当前情况不同。

我喜欢调用HTTP-Ping的过程要求您只触摸特定的URI,强制特定服务器启动它的内部逻辑。某些功能允许您通过不等待响应来实现与此 HTTP-ping 非常相似的功能。

请注意 ping 网址的过程分为两个步骤:

  1. 解析DNS
  2. 提出请求
  3. 虽然在解析DNS并建立连接后,请求应该相当快,但DNS解析速度的方法并不多。

    进行http-ping的一些方法是:

    1. cURL,将CONNECTION_TIMEOUT设置为较低的值
    2. fsockopen写完后立即关闭
    3. stream_socket_client(与fsockopen相同)并添加STREAM_CLIENT_ASYNC_CONNECT
    4. 虽然正在解析DNS,cURLfsockopen都会阻塞。我注意到 fsockopen 明显更快,即使在最坏的情况下也是如此。

      另一方面,

      stream_socket_client应该解决有关DNS解析的问题,并且应该是这种情况下的最佳解决方案,但我还没有设法让它工作。

      最后一个解决方案是启动另一个为您执行此操作的线程/进程。为此系统调用应该有效,但forking当前进程也应该这样做。不幸的是,在无法控制运行PHP的环境的应用程序中,两者都不是很安全。

      系统调用通常被阻止,默认情况下不启用pcntl。

答案 1 :(得分:13)

我会这样调用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;

答案 2 :(得分:10)

我实现了对url的快速GET请求的功能,而无需等待响应:

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

答案 3 :(得分:3)

您可以使用shell_exec和命令行卷曲。

有关示例,请参阅this question

答案 4 :(得分:1)

在研究类似问题的同时来到这里。如果你有一个方便的数据库连接,另一种可能是快速将请求详细信息填充到表中,然后有一个单独的基于cron的进程,定期扫描该表以处理新记录,并发出跟踪请求,释放您的Web应用程序必须自己发出HTTP请求。

答案 5 :(得分:1)

我们使用了fsockopenfwrite组合,然后有一天它停止工作。还是有点断断续续。经过一些研究和测试,并且如果您启用了fopen包装器,我最终使用了file_get_contentsstream_context_create函数,并将超时设置为100秒。超时参数可以接收浮点值(https://www.php.net/manual/en/context.http.php)。我将其包装在try ... catch块中,因此它将无声地失败。它很适合我们的目的。如果需要,您可以在捕获中进行日志记录。如果您不希望函数阻止运行时,则超时是关键。

function fetchWithoutResponseURL( $url )
{

    $context = stream_context_create([
        "http" => [
            "method"=>"GET",
            "timeout" => .01
            ]
        ]
    );

    try {
        file_get_contents($url, 0, $context);
    }catch( Exception $e ){
        // Fail silently
    }
}

答案 6 :(得分:0)

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

答案 7 :(得分:0)

我需要做类似的事情,只需ping一个网址并丢弃所有回复。我使用了proc_open命令,它允许你使用proc_close立即结束进程。我假设你的服务器上安装了lynx:

<?php    
function ping($url) {
      $proc = proc_open("lynx $url",[],$pipes);
      proc_close($proc);
    }
?>

答案 8 :(得分:0)

对于那些使用wordrpess作为后端的人- 它很简单:

wp_remote_get( $url, array(blocking=>false) );

答案 9 :(得分:-1)

您实际上可以直接使用CURL执行此操作。

我已经使用非常短暂的超时(CURLOPT_TIMEOUT_MS)和/或使用curl_multi_exec实现了它。

建议:最终我退出此方法,因为并非每个请求都是正确的。这可能是由我自己的服务器造成的,虽然我无法排除卷曲失败的选项。