1. 什么是Guzzle?

Guzzle是一个PHP的HTTP客户端,用来轻而易举地发送请求,并集成到我们的WEB服务上。

  • 接口简单:构建查询语句、POST请求、分流上传下载大文件、使用HTTP cookies、上传JSON数据等等。
  • 发送同步或异步的请求均使用相同的接口。
  • 使用PSR-7接口来请求、响应、分流,允许你使用其他兼容的PSR-7类库与Guzzle共同开发。
  • 抽象了底层的HTTP传输,允许你改变环境以及其他的代码,如:对cURL与PHP的流或socket并非重度依赖,非阻塞事件循环。
  • 中间件系统允许你创建构成客户端行为。

Github地址:guzzle/guzzle

官方文档:http://docs.guzzlephp.org/en/stable/

中文文档:http://guzzle-cn.readthedocs.io/zh_CN/latest/

2. 安装Guzzle

2.1 通过composer安装

执行composer命令:

php composer.phar require guzzlehttp/guzzle

引入Composer自动加载类:

require ‘vendor/autoload.php’;

通过Composer更新Guzzle:

composer.phar update

3. 例子

$client = new \GuzzleHttp\Client();
$res = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');
echo $res->getStatusCode();
// 200
echo $res->getHeaderLine('content-type');
// 'application/json; charset=utf8'
echo $res->getBody();
// '{"id": 1420053, "name": "guzzle", ...}'

// 发送一个异步请求
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org');
$promise = $client->sendAsync($request)->then(function ($response) {
    echo 'I completed! ' . $response->getBody();
});
$promise->wait();

4. 发送请求

4.1 创建客户端

通过实例化Client类创建一个客户端:

<?php
use GuzzleHttp\Client;

$client = new Client([
    // 基URI
    'base_uri' => 'http://httpbin.org',
    // 设置默认请求参数
    'timeout'  => 2.0,
]);

4.2 发送请求

Client对象的方法可以很容易的发送请求:

<?php 
$response = $client->get('http://httpbin.org/get');
$response = $client->delete('http://httpbin.org/delete');
$response = $client->head('http://httpbin.org/get');
$response = $client->options('http://httpbin.org/get');
$response = $client->patch('http://httpbin.org/patch');
$response = $client->post('http://httpbin.org/post');
$response = $client->put('http://httpbin.org/put');

或者创建一个请求,一切就绪后再发送请求:

<?php
use GuzzleHttp\Psr7\Request;

$request = new Request('PUT', 'http://httpbin.org/put');
$response = $client->send($request, ['timeout' => 2]);

4.3 异步请求

直接用Client提供的方法来创建异步请求:

<?php 
$promise = $client->getAsync('http://httpbin.org/get');
$promise = $client->deleteAsync('http://httpbin.org/delete');
$promise = $client->headAsync('http://httpbin.org/get');
$promise = $client->optionsAsync('http://httpbin.org/get');
$promise = $client->patchAsync('http://httpbin.org/patch');
$promise = $client->postAsync('http://httpbin.org/post');
$promise = $client->putAsync('http://httpbin.org/put');

或者使用Client的 sendAsync() and requestAsync() 方法:

<?php 
// 创建一个PSR-7请求对象 $headers = ['X-Foo' => 'Bar'];
$body = 'Hello!';
$request = new Request('HEAD', 'http://httpbin.org/head', $headers, $body);

// 如果不需要进去请求实例
$promise = $client->requestAsync('GET', 'http://httpbin.org/get');

使用 then() 来调用返回值,成功使用 Psr\Http\Message\ResponseInterface 处理器,否则抛出一个异常:

<?php
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;

$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
$promise->then(
    function (ResponseInterface $res) {
        echo $res->getStatusCode() . "\n";
    },
    function (RequestException $e) {
        echo $e->getMessage() . "\n";
        echo $e->getRequest()->getMethod();
    }
);

4.4 并发请求

使用Promise和异步请求来同时发送多个请求:

<?php
use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client(['base_uri' => 'http://httpbin.org/']);

// 初始化每一个非阻塞请求
$promises = [
    'image' => $client->getAsync('/image'),
    'png'   => $client->getAsync('/image/png'),
    'jpeg'  => $client->getAsync('/image/jpeg'),
    'webp'  => $client->getAsync('/image/webp')
];

// 等待请求完成
$results = Promise\unwrap($promises);

// 通过键名接收每一个结果
// function.
echo $results['image']->getHeader('Content-Length');
echo $results['png']->getHeader('Content-Length');

当你想发送不确定数量的请求时,可以使用 GuzzleHttp\Pool 对象:

<?php
use GuzzleHttp\Pool;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;

$client = new Client();

$requests = function ($total) {
    $uri = 'http://127.0.0.1:8126/guzzle-server/perf';
    for ($i = 0; $i < $total; $i++) {
        yield new Request('GET', $uri);
    }
};

$pool = new Pool($client, $requests(100), [
    'concurrency' => 5,
    'fulfilled' => function ($response, $index) {
        // 每个成功的请求
    },
    'rejected' => function ($reason, $index) {
        // 每个失败的请求
    },
]);

// 初始化传输和创建授权
$promise = $pool->promise();

// 等待请求池完成
$promise->wait();

5. 响应

5.1 获取响应的状态码

$code = $response->getStatusCode(); // 200

5.2 获取原因短语(reason phrase)

$reason = $response->getReasonPhrase(); // OK

5.3 获取头信息(header)

// 检查是否存在头信息
if ($response->hasHeader('Content-Length')) {
    echo "It exists";
}

// 获取头信息
echo $response->getHeader('Content-Length');

// 获取所有响应头信息
foreach ($response->getHeaders() as $name => $values) {
    echo $name . ': ' . implode(', ', $values) . "\r\n";
}

5.4 获取响应的主体部分(body)

$body = $response->getBody();
// 隐式转换成字符串并输出
echo $body;
// 显示转换body成字符串
$stringBody = (string) $body;
// 从body中读取10字节(bytes)
$tenBytes = $body->read(10);
// 将正文的剩余内容作为字符串读取
$remainingBytes = $body->getContents();

6. 参数

6.1 在请求的URI中设置查询字符串

$response = $client->request('GET', 'http://httpbin.org?foo=bar');

6.2 使用 query 请求参数来声明查询字符串参数

$client->request('GET', 'http://httpbin.org', [
    'query' => ['foo' => 'bar']
]);

6.3 提供一个字符串作为 query 请求参数

$client->request('GET', 'http://httpbin.org', ['query' => 'foo=bar']);

7. 其它

Guzzle还提供了一些其它有用的功能

具体的可以查看官方文档。