异步 HTTP 请求帮助我们在不同线程中使用非阻塞输入或输出处理 HTTP 请求。有些人将其称为 COMET 能力。异步 HTTP 请求的主要用途是当客户端向服务器请求延迟响应时。一个常见的例子是 AJAX 聊天客户端,我们从客户端和服务器推送或拉取。这些场景会在服务器的套接字上阻塞客户端长时间等待新消息。
PHP同步处理请求。这意味着每一行代码都以脚本的同步方式执行。从一行获取结果后,它执行下一行或等待结果,然后跳转到下一行代码的执行。在某些情况下,我们应该向 URL 发出请求并且它们不相互依赖。在这种情况下,我们不想等待一个请求的结果来执行其他请求。因此,我们发出异步请求。
Guzzle 6: Guzzle 是一个PHP HTTP 客户端,帮助发送 HTTP 请求。这些方法可用于发送异步 HTTP 请求。
- 请求异步,
- 发送异步,
- 获取异步,
- 头异步,
- 放置异步,
- 异步后,
- 删除异步,
- 补丁异步
下载 Guzzle PHP包。可以通过 composer 安装。
php composer.phar require guzzlehttp/guzzle:~6.0
或者
composer require guzzlehttp/guzzle:~6.0
请在代码的脚本部分包含“自动加载”文件,以便它加载所有类和方法。
PHP
getAsync('http://localhost')
->then(function ($response)
{ echo '10'; }),
$client->getAsync('http://www.google.com')
->then(function ($response)
{ echo '20'; }),
$client->getAsync('http://localhost')
->then(function ($response)
{ echo '30'; }),
$client->getAsync('http://localhost')
->then(function ($response)
{ echo '40'; }),
$client->getAsync('http://localhost')
->then(function ($response)
{ echo '50'; }),
$client->getAsync('http://localhost')
->then(function ($response)
{ echo '60'; }),
$client->getAsync('http://localhost')
->then(function ($response)
{ echo '70'; }),
];
$results = GuzzleHttp\Promise\unwrap($promises);
// Please wait for a while to complete
// the requests(some of them may fail)
$results = GuzzleHttp\Promise\settle(
$promises)->wait();
print "finish/over." . PHP_EOL;
?>
PHP
getAsync(
'https://api.demo.com/v1/users?username='
. $user);
}
})();
$eachPromise = new EachPromise($promises, [
// Number of concurrency
'concurrency' => 4,
'fulfilled' => function (Response $response) {
if ($response->getStatusCode() == 200) {
$user = json_decode(
$response->getBody(), true);
// processing response of the user
}
},
'rejected' => function ($reason) {
// handle promise rejected
}
]);
$eachPromise->promise()->wait();
?>
在上面的代码中,包含了“自动加载”文件,然后创建了 Guzzle Http 客户端对象,该对象存储在“客户端”变量中,并且对于每个 Http 请求,将getAsync()方法与 URL 一起使用。
获得第一个响应的请求将打印数字。请求的顺序无关紧要。
使用 Promise 的异步 HTTP 请求:异步操作的单个结果代表一个Promise 。异步请求用于 HTTP 操作的非阻塞。当异步 HTTP 请求发送承诺时,它会被返回。
使用 HTTPlug 执行请求:
$request = $messageFactory->createRequest(
'GET', 'http://php-http.org');
$promise = $client->sendAsyncRequest($request);
echo 'Non-blocking!';
等待:从上面返回的“promise”,实现了http\Promise\Promise 。在这个时间点上,响应尚不可知。等待那个回应的到来。
try {
$response = $promise->wait();
} catch (\Exception $exception) {
echo $exception->getMessage();
}
然后:我们可以异步执行步骤,而不是等待。使用两个参数调用then方法。
- 如果请求成功,将执行的一个回调。
- 如果请求导致错误,将执行的回调。
// Success Callback
function (ResponseInterface $response) {
echo 'New response!';
// Write status code to the log file
file_put_contents('responses.log',
$response->getStatusCode() . "\n", FILE_APPEND);
return $response;
},
// Failure Callback
function (\Exception $exception) {
echo 'We have a problem';
throw $exception;
}
Promise 中的并发:并发意味着多个计算同时发生。当我们同时处理很多请求时很好。对于并发,我们必须使用“EachPromise”类和yield生成器,最后在程序末尾添加wait() 。
PHP
getAsync(
'https://api.demo.com/v1/users?username='
. $user);
}
})();
$eachPromise = new EachPromise($promises, [
// Number of concurrency
'concurrency' => 4,
'fulfilled' => function (Response $response) {
if ($response->getStatusCode() == 200) {
$user = json_decode(
$response->getBody(), true);
// processing response of the user
}
},
'rejected' => function ($reason) {
// handle promise rejected
}
]);
$eachPromise->promise()->wait();
?>
构建多线程cURL请求:一般我们可以处理多个请求。首先,我们触发第一个并处理响应,然后是第二个和第三个,依此类推。但是,此过程缓慢且耗时。但是 cURL 提供curl_multi_*函数来处理任何 asnyc 请求。
$running = null;
$mh = curl_multi_init();
$ch1 = curl_init();
curl_setopt($ch1, CURLOPT_URL, 'https://endpoint.com');
// Other curl options....
curl_multi_add_handle($mh, $ch1);
$ch2 = curl_init();
curl_setopt($ch2, CURLOPT_URL, 'https://endpoint.com');
// Other curl options....
curl_multi_add_handle($mh, $ch2);
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
$r1 = curl_multi_getcontent($ch1);
$r2 = curl_multi_getcontent($ch2);
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);
响应被收集在“r1”和“r2”变量中。借助这些 cURL 函数,我们可以并行触发请求以节省时间并更快地处理响应。