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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14359926/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 07:08:17  来源:igfitidea点击:

Send HTTP request from PHP without waiting for response?

phphttpcurlserver-sideweb-analytics

提问by feklee

I want to have an HTTP GET request sent from PHP. Example:

我想从 PHP 发送一个 HTTP GET 请求。例子:

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

The idea is to do server-side web-analytics: Instead of sending tracking information from JavaScript to a server, the server sends tracking information directly to another server.

其想法是进行服务器端 Web 分析:服务器不会将跟踪信息从 JavaScript 发送到服务器,而是直接将跟踪信息发送到另一台服务器。

Requirements:

要求:

  • The request should take as little time as possible, in order to not noticeably delay processing of the PHP page.

  • The response from the tracker.example.comdoes not need to be checked. As examples, some possible responses from tracker.example.com:

    • 200:That's fine, but no need to check that.

    • 404:Bad luck, but - again - no need to check that.

    • 301:Although a redirect would be appropriate, it would delay processing of the PHP page, so don't do that.

    In short: Allresponses can be discarded.

  • 该请求应花费尽可能少的时间,以免明显延迟 PHP 页面的处理。

  • tracker.example.com不需要检查来自 的响应。例如,一些可能的回应来自 tracker.example.com

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

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

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

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

Ideas for solutions:

解决方案的想法:

  • In a now deleted answer, someone suggested calling command line curlfrom PHP in a shell process. This seems like a good idea, only that I don't know if forking a lot of shell processes under heavy load is a wise thing to do.

  • I found php-ga, a package for doing server-side Google Analytics from PHP. On the project's page, it is mentioned: "Can be configured to [...] use non-blocking requests."So far I haven't found the time to investigate what method php-ga uses internally, but this method could be it!

  • 在现已删除的答案中,有人建议在 shell 进程中从 PHP调用命令行 curl。这似乎是个好主意,只是我不知道在重负载下分叉大量 shell 进程是否明智。

  • 我找到了php-ga,这是一个用于从 PHP 进行服务器端 Google Analytics 的包。在项目页面上,提到:“可以配置为 [...] 使用非阻塞请求。” 到目前为止我还没有时间去调查php-ga内部使用什么方法,但这个方法可能就是它!

In a nutshell: What is the best solution to do generic server-side tracking/analytics from PHP.

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

采纳答案by Khez

Unfortunately PHP by definition is blocking. While this holds true for the majority of functions and operations you will normally be handling, the current scenario is different.

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

The process which I like to call HTTP-Ping, requires that you only toucha specific URI, forcing the specific server to boot-strap it's internal logic. Some functions allow you to achieve something very similar to this HTTP-ping, by not waiting for a response.

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

Take note that the process of pingingan url, is a two step process:

请注意,pingurl的过程是一个两步过程:

  1. Resolve the DNS
  2. Making the request
  1. 解析 DNS
  2. 提出请求

While making the request should be rather fast once the DNS is resolved and the connection is made, there aren't many ways of making the DNS resolve faster.

虽然在解析 DNS 并建立连接后发出请求应该相当快,但没有很多方法可以使 DNS 解析更快。

Some ways of doing an http-ping are:

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

  1. cURL, by setting CONNECTION_TIMEOUT to a low value
  2. fsockopenby closing immediately after writing
  3. stream_socket_client(same as fsockopen) and also adding STREAM_CLIENT_ASYNC_CONNECT
  1. cURL,通过将 CONNECTION_TIMEOUT 设置为低值
  2. fsockopen写入后立即关闭
  3. stream_socket_client(与 fsockopen 相同)并添加STREAM_CLIENT_ASYNC_CONNECT

While both cURLand fsockopenare both blocking while the DNS is being resolved. I have noticed that fsockopenis significantly faster, even in worst case scenarios.

虽然cURLfsockopen都在解析 DNS 时阻塞。我注意到fsockopen明显更快,即使在最坏的情况下也是如此。

stream_socket_clienton the other hand should fix the problem regarding DNS resolving and should be the optimal solution in this scenario, but I have not managed to get it to work.

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

One final solution is to start another thread/process that does this for you. Making a system call for this should work, but also forkingthe current process should do that also. Unfortunately both are not really safe in applications where you can't control the environment on which PHP is running.

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

System calls are more often than not blocked and pcntl is not enabled by default.

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

回答by RafaSashi

I would call tracker.example.com this way:

我会这样调用 tracker.example.com:

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

and in the tracker 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;

回答by CETb

I implemented function for fast GET request to url without waiting for response:

我实现了快速 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);
}

回答by Dutow

You can use shell_exec, and command line curl.

您可以使用shell_exec, 和命令行 curl。

For an example, see this question

例如,请参阅此问题

回答by HP Autonomy Webmaster

Came here whilst researching a similar problem. If you have a database connection handy, one other possibility is to quickly stuff the request details into a table, and then have a seperate cron-based process that periodically scans that table for new records to process, and makes the tracking request, freeing up your web application from having to make the HTTP request itself.

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

回答by Yair Levy

For those of you working with wordrpess as a backend - it is as simple as:

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

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

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

回答by Gerald Melendez

I needed to do something similar, just ping a url and discard all responses. I used the proc_open command which lets you end the process right away using proc_close. I'm assuming you have lynx installed on your server:

我需要做一些类似的事情,只需 ping 一个 url 并丢弃所有响应。我使用了 proc_open 命令,它可以让您使用 proc_close 立即结束进程。我假设您的服务器上安装了 lynx:

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

回答by Ali

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

回答by DoXicK

You can actually do this using CURLdirectly.

您实际上可以CURL直接使用。

I have both implemented it using a very short timeout (CURLOPT_TIMEOUT_MS) and/or using curl_multi_exec.

我都使用非常短的超时 ( CURLOPT_TIMEOUT_MS) 和/或使用curl_multi_exec.

Be advised: eventually i quit this method because not every request was correctly made. This could have been caused by my own server though i haven't been able to rule out the option of curl failing.

请注意:最终我退出了此方法,因为并非每个请求都正确提出。这可能是由我自己的服务器引起的,尽管我无法排除 curl 失败的选项。