2019-03-31 22:48:29 +08:00
|
|
|
|
# Guzzle HTTP 客户端
|
|
|
|
|
|
|
|
|
|
[hyperf/guzzle](https://github.com/hyperf-cloud/guzzle) 组件基于 Guzzle 进行协程处理,通过 Swoole HTTP 客户端作为协程驱动替换到 Guzzle 内,以达到 HTTP 客户端的协程化。
|
|
|
|
|
|
|
|
|
|
## 安装
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
composer require hyperf/guzzle
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 使用
|
|
|
|
|
|
|
|
|
|
只需要该组件内的 `Hyperf\Guzzle\CoroutineHandler` 作为处理器设置到 Guzzle 客户端内即可转为协程化运行,为了方便创建协程的 Guzzle 对象,我们提供了一个工厂类 `Hyperf\Guzzle\ClientFactory` 来便捷的创建客户端,代码示例如下:
|
|
|
|
|
|
|
|
|
|
```php
|
2019-05-06 15:18:45 +08:00
|
|
|
|
<?php
|
|
|
|
|
use Hyperf\Guzzle\ClientFactory;
|
|
|
|
|
|
|
|
|
|
class Foo {
|
|
|
|
|
/**
|
|
|
|
|
* @var \Hyperf\Guzzle\ClientFactory
|
|
|
|
|
*/
|
|
|
|
|
private $clientFactory;
|
|
|
|
|
|
|
|
|
|
public function __construct(ClientFactory $clientFactory)
|
|
|
|
|
{
|
|
|
|
|
$this->clientFactory = $clientFactory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function bar()
|
|
|
|
|
{
|
|
|
|
|
// $options 等同于 GuzzleHttp\Client 构造函数的 $config 参数
|
|
|
|
|
$options = [];
|
|
|
|
|
// $client 为协程化的 GuzzleHttp\Client 对象
|
|
|
|
|
$client = $this->clientFactory->create($options);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-06 14:08:47 +08:00
|
|
|
|
```
|
|
|
|
|
|
2019-07-12 09:42:34 +08:00
|
|
|
|
## 使用Swoole配置
|
|
|
|
|
|
|
|
|
|
有时候我们想直接修改 `Swoole` 配置,所以我们也提供了相关配置项,不过这项配置在 `Curl Guzzle 客户端` 中是无法生效的,所以谨慎使用。
|
|
|
|
|
|
|
|
|
|
> 这项配置会替换原来的配置,比如以下 timeout 会被 10 替换。
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
<?php
|
|
|
|
|
use GuzzleHttp\Client;
|
|
|
|
|
use Hyperf\Guzzle\CoroutineHandler;
|
|
|
|
|
use GuzzleHttp\HandlerStack;
|
|
|
|
|
|
|
|
|
|
$client = new Client([
|
|
|
|
|
'base_uri' => 'http://127.0.0.1:8080',
|
|
|
|
|
'handler' => HandlerStack::create(new CoroutineHandler()),
|
|
|
|
|
'timeout' => 5,
|
|
|
|
|
'swoole' => [
|
|
|
|
|
'timeout' => 10,
|
|
|
|
|
'socket_buffer_size' => 1024 * 1024 * 2,
|
|
|
|
|
],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$response = $client->get('/');
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2019-06-06 14:08:47 +08:00
|
|
|
|
## 连接池
|
|
|
|
|
|
|
|
|
|
Hyperf 除了实现了 `Hyperf\Guzzle\CoroutineHandler` 外,还基于 `Hyperf\Pool\SimplePool` 实现了 `Hyperf\Guzzle\PoolHandler`。
|
|
|
|
|
|
|
|
|
|
### 原因
|
|
|
|
|
|
2019-06-06 14:10:45 +08:00
|
|
|
|
简单来说,主机 TCP连接数 是有上限的,当我们并发大到超过这个上限值时,就导致请求无法正常建立。另外,TCP连接结束后还会有一个 TIME-WAIT 阶段,所以也无法实时释放连接。这就导致了实际并发可能远低于 TCP 上限值。所以,我们需要一个连接池来维持这个阶段,尽量减少 TIME-WAIT 造成的影响,让TCP连接进行复用。
|
2019-06-06 14:08:47 +08:00
|
|
|
|
|
|
|
|
|
### 使用
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
use GuzzleHttp\Client;
|
|
|
|
|
use Hyperf\Utils\Coroutine;
|
|
|
|
|
use GuzzleHttp\HandlerStack;
|
|
|
|
|
use Hyperf\Guzzle\PoolHandler;
|
|
|
|
|
use Hyperf\Guzzle\RetryMiddleware;
|
|
|
|
|
|
|
|
|
|
function default_guzzle_handler(): HandlerStack
|
|
|
|
|
{
|
|
|
|
|
$handler = null;
|
|
|
|
|
if (Coroutine::inCoroutine()) {
|
|
|
|
|
$handler = make(PoolHandler::class, [
|
|
|
|
|
'option' => [
|
|
|
|
|
'max_connections' => 50,
|
|
|
|
|
],
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 默认的重试Middleware
|
|
|
|
|
$retry = make(RetryMiddleware::class, [
|
|
|
|
|
'retries' => 1,
|
|
|
|
|
'delay' => 10,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$stack = HandlerStack::create($handler);
|
|
|
|
|
$stack->push($retry->getMiddleware(), 'retry');
|
|
|
|
|
|
|
|
|
|
return $stack;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$client = make(Client::class, [
|
|
|
|
|
'config' => [
|
|
|
|
|
'handler' => default_guzzle_handler(),
|
|
|
|
|
],
|
|
|
|
|
]);
|
2019-03-31 22:48:29 +08:00
|
|
|
|
```
|