PHP中是否有一种方法可以使HTTP调用不等待响应?我不关心响应,我只想做一些类似file_get_contents()的事情,但不等待请求完成后再执行其余的代码。这对于在我的应用程序中触发某种“事件”或触发长进程非常有用。
什么好主意吗?
PHP中是否有一种方法可以使HTTP调用不等待响应?我不关心响应,我只想做一些类似file_get_contents()的事情,但不等待请求完成后再执行其余的代码。这对于在我的应用程序中触发某种“事件”或触发长进程非常有用。
什么好主意吗?
当前回答
你可以在PHP中使用非阻塞套接字和pecl扩展之一:
http://php.net/event http://php.net/libevent http://php.net/ev https://github.com/m4rw3r/php-libev
您可以使用库,它为您的代码和pecl扩展之间提供了一个抽象层:https://github.com/reactphp/event-loop
您还可以使用基于前面库的异步http-client: https://github.com/reactphp/http-client
查看ReactPHP的其他库:http://reactphp.org
使用异步模型时要小心。 我推荐在youtube上看这个视频:http://www.youtube.com/watch?v=MWNcItWuKpI
其他回答
我之前接受的答案行不通。它仍在等待回应。这虽然工作,采取从我如何使一个异步GET请求在PHP?
function post_without_wait($url, $params)
{
foreach ($params as $key => &$val) {
if (is_array($val)) $val = implode(',', $val);
$post_params[] = $key.'='.urlencode($val);
}
$post_string = implode('&', $post_params);
$parts=parse_url($url);
$fp = fsockopen($parts['host'],
isset($parts['port'])?$parts['port']:80,
$errno, $errstr, 30);
$out = "POST ".$parts['path']." HTTP/1.1\r\n";
$out.= "Host: ".$parts['host']."\r\n";
$out.= "Content-Type: application/x-www-form-urlencoded\r\n";
$out.= "Content-Length: ".strlen($post_string)."\r\n";
$out.= "Connection: Close\r\n\r\n";
if (isset($post_string)) $out.= $post_string;
fwrite($fp, $out);
fclose($fp);
}
swoole扩展。https://github.com/matyhtf/swoole PHP的异步并发网络框架。
$client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
$client->on("connect", function($cli) {
$cli->send("hello world\n");
});
$client->on("receive", function($cli, $data){
echo "Receive: $data\n";
});
$client->on("error", function($cli){
echo "connect fail\n";
});
$client->on("close", function($cli){
echo "close\n";
});
$client->connect('127.0.0.1', 9501, 0.5);
您可以使用exec()来调用一些可以执行HTTP请求的东西,如wget,但必须将程序的所有输出指向某个地方,如文件或/dev/null,否则PHP进程将等待该输出。
如果你想把进程和apache线程完全分开,可以尝试这样做(我不确定,但我希望你能明白):
exec('bash -c "wget -O (url goes here) > /dev/null 2>&1 &"');
这不是一项很好的业务,您可能需要类似cron作业的东西来调用heartbeat脚本,该脚本轮询实际的数据库事件队列来执行真正的异步事件。
Symfony HttpClient是异步的https://symfony.com/doc/current/components/http_client.html。
例如,你可以
use Symfony\Component\HttpClient\HttpClient;
$client = HttpClient::create();
$response1 = $client->request('GET', 'https://website1');
$response2 = $client->request('GET', 'https://website1');
$response3 = $client->request('GET', 'https://website1');
//these 3 calls with return immediately
//but the requests will fire to the website1 webserver
$response1->getContent(); //this will block until content is fetched
$response2->getContent(); //same
$response3->getContent(); //same
截至2018年,Guzzle已经成为HTTP请求事实上的标准库,在几个现代框架中使用。它是用纯PHP编写的,不需要安装任何自定义扩展。
它可以很好地执行异步HTTP调用,甚至可以在需要执行100个HTTP调用,但不想一次运行超过5个的情况下将它们合并在一起。
并发请求示例
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
$client = new Client(['base_uri' => 'http://httpbin.org/']);
// Initiate each request but do not block
$promises = [
'image' => $client->getAsync('/image'),
'png' => $client->getAsync('/image/png'),
'jpeg' => $client->getAsync('/image/jpeg'),
'webp' => $client->getAsync('/image/webp')
];
// Wait on all of the requests to complete. Throws a ConnectException
// if any of the requests fail
$results = Promise\unwrap($promises);
// Wait for the requests to complete, even if some of them fail
$results = Promise\settle($promises)->wait();
// You can access each result using the key provided to the unwrap
// function.
echo $results['image']['value']->getHeader('Content-Length')[0]
echo $results['png']['value']->getHeader('Content-Length')[0]
看到http://docs.guzzlephp.org/en/stable/quickstart.html并发请求