Guzzle 几乎成为了 PHP 语言中事实上的 HTTP 标准库,WordPress 在新版本的 JSON API 插件中,已经弃用了 WP HTTP API ,而使用 Guzzle 进行开发,指不定哪一天 WP HTTP API 会被彻底启用,转而全面使用 Guzzle,如果你以前没有接触过 Guzzle,下面是一些快速入门以及列子。
发送请求
我们可以使用 Guzzle的 GuzzleHttp\ClientInterface 对象来发送请求。
创建客户端
复制
use GuzzleHttp\Client;
$client = new Client([ // 相对请求的基础 URI 'base_uri' => 'http://httpbin.org', // 可以设置请求的默认超时时间 'timeout'
Client 对象可以接收一个包含参数的数组:
base_uri 基础 URI
(string|UriInterface) 基 URI 用来合并到相关 URI,可以是一个字符串或者 UriInterface 的实例,当提供了相关 URL,将合并到基 URI,遵循的规则请参考 RFC 3986, section 2 章节。
复制
// 使用 基础 URI 创建一个客户端
$client = new GuzzleHttp\Client(['base_uri' => 'https://foo.com/api/']);
// 发送一个请求到 https://foo.com/api/test
$response = $client->request('GET', 'test');
// 发送一个请求到 https://foo.com/root
$response = $client->request('GET', '/root');
不想阅读 RFC 3986?这里有一些关于 base_uri 与其他 URI 处理器的快速例子:
base_uri URI Result
http://foo.com /bar http://foo.com/bar
http://foo.com/foo /bar http://foo.com/bar
http://foo.com/foo bar http://foo.com/bar
http://foo.com/foo/ bar http://foo.com/foo/bar
http://foo.com http://baz.com http://baz.com
http://foo.com/?bar bar http://foo.com/bar
handler HTTP 头信息
传输HTTP请求的(回调)函数。 该函数被调用的时候包含 Psr7\Http\Message\RequestInterface 以及参数数组,必须返回 GuzzleHttp\Promise\PromiseInterface ,成功时满足 Psr7\Http\Message\ResponseInterface 。 handler 是一个构造方法,不能在请求参数里被重写。
…
(混合) 构造方法中传入的其他所有参数用来当作每次请求的默认参数。
发送请求
Client 对象的方法可以很容易的发送请求:
复制
$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');
你可以创建一个请求,一切就绪后将请求传送给 Client:
复制
use GuzzleHttp\Psr7\Request;
$request = new Request('PUT', 'http://httpbin.org/put'); $response = $client->send($request, ['timeout' => 2]);
Client 对象为传输请求提供了非常灵活的处理器方式,包括请求参数、每次请求使用的中间件以及传送多个相关请求的基URI。
你可以在 Handlers and Middleware 页面找到更多关于中间件的内容。
异步请求
你可以使用 Client 提供的方法来创建异步请求:
复制
$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() 方法:
复制
use GuzzleHttp\Psr7\Request;
// Create a PSR-7 request object to send
$headers = ['X-Foo' => 'Bar'];
$body = 'Hello!';
$request = new Request('HEAD', 'http://httpbin.org/head', $headers, $body);
// Or, if you don't need to pass in a request instance:
$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
这些方法返回了 Promise 对象,该对象实现了由 Guzzle promises library 提供的 Promises/A+ spec ,这意味着你可以使用 then() 来调用返回值,成功使用 Psr\Http\Message\ResponseInterface 处理器,否则抛出一个异常。
复制
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();
}
);
并发请求
你可以使用 Promise 和异步请求来同时发送多个请求:
复制
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);
// You can access each result using the key provided to the unwrap function.
echo $results['image']->getHeader('Content-Length');
echo $results['png']->getHeader('Content-Length');
当你想发送不确定数量的请求时,可以使用 GuzzleHttp\Pool 对象:
复制
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
$promise = $pool->promise();
// 等待请求池完成
$promise->wait();
使用响应
前面的例子里,我们取到了 $response 变量,或者从 Promise 得到了响应,Response 对象实现了一个 PSR-7 接口Psr\Http\Message\ResponseInterface ,包含了很多有用的信息。
你可以获取这个响应的状态码和和原因短语 (reason phrase):
复制
$code = $response->getStatusCode(); // 200
$reason = $response->getReasonPhrase(); // OK
你可以从响应获取头信息 (header):
复制
// 检查 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";
}
使用 getBody 方法可以获取响应的主体部分 (body),主体可以当成一个字符串或流对象使用
复制
$body = $response->getBody();
// 直接作为字符串显示 body
echo $body;
// 作为一个字符串赋值 body 给一个变量
$stringBody = (string) $body;
// 读取 body 内容的前 10 字节
$tenBytes = $body->read(10);
// 作为字符串读取剩下的 body 内容Read
$remainingBytes = $body->getContents();
查询字符串参数
你可以有多种方式来提供请求的查询字符串 你可以在请求的 URI 中设置查询字符串:
复制
$response = $client->request('GET', 'http://httpbin.org?foo=bar');
你可以使用 query 请求参数来声明查询字符串参数:
复制
$client->request('GET', 'http://httpbin.org', [
'query' => ['foo' => 'bar']
]);
提供的数组参数将会使用 PHP 的 http_build_query :
最后,你可以提供一个字符串作为 query 请求参数:
复制
$client->request('GET', 'http://httpbin.org', ['query' => 'foo=bar']);
上传数据
Guzzle 为上传数据提供了一些方法。 你可以发送一个包含数据流的请求,将 body 请求参数设置成一个字符串、fopen 返回的资源、或者一个 Psr\Http\Message\StreamInterface 的实例。
复制
// 作为字符串提供 body 内容
$r = $client->request('POST', 'http://httpbin.org/post', [
'body' => 'raw data'
]);
// 提供一个 fopen 资源
$body = fopen('/path/to/file', 'r');
$r = $client->request('POST', 'http://httpbin.org/post', ['body' => $body]);
// 使用 stream_for() 函数创建一个 PSR-7 stream.
$body = \GuzzleHttp\Psr7\stream_for('hello!');
$r = $client->request('POST', 'http://httpbin.org/post', ['body' => $body]);
上传 JSON 数据以及设置合适的头信息可以使用 json 请求参数这个简单的方式:
复制
$r = $client->request('PUT', 'http://httpbin.org/put', [
'json' => ['foo' => 'bar']
]);
POST/表单请求
除了使用 body 参数来指定请求数据外,Guzzle 为发送 POST 数据提供了有用的方法。
发送表单字段
发送 application/x-www-form-urlencoded POST 请求需要你传入 form_params 数组参数,数组内指定 POST 的字段。
复制
$response = $client->request('POST', 'http://httpbin.org/post', [
'form_params' => [
'field_name' => 'abc',
'other_field' => '123',
'nested_field' => [
'nested' => 'hello'
]
]
]);
发送表单文件
你可以通过使用 multipart 请求参数来发送表单(表单enctype属性需要设置 multipart/form-data )文件, 该参数接收一个包含多个关联数组的数组,每个关联数组包含一下键名:
name: (必须,字符串) 映射到表单字段的名称。
contents: (必须,混合) 提供一个字符串,可以是 fopen 返回的资源、或者一个
Psr\Http\Message\StreamInterface 的实例。
复制
response = $client->request('POST', 'http://httpbin.org/post', [
'multipart' => [
[
'name' => 'field_name',
'contents' => 'abc'
],
[
'name' => 'file_name',
'contents' => fopen('/path/to/file', 'r')
],
[
'name' => 'other_file',
'contents' => 'hello',
'filename' => 'filename.txt',
'headers' => [
'X-Foo' => 'this is an extra header to include'
]
]
]
]);
Cookies
Guzzle 可以使用 cookies 请求参数为你维护一个 cookie会话,当发送一个请求时, cookies 选项必须设置成 GuzzleHttp\Cookie\CookieJarInterface 的实例。
复制
// 使用一个指定的 cookie
$jar = new \GuzzleHttp\Cookie\CookieJar;
$r = $client->request('GET', 'http://httpbin.org/cookies', [
'cookies' => $jar
]);
如果你想在所有的请求中共享 Cookies, 你可以在客户端构造器中设置 Cookies 为 true。
复制
// 使用共 cookie 的客户端
$client = new \GuzzleHttp\Client(['cookies' => true]);
$r = $client->request('GET', 'http://httpbin.org/cookies');
重定向
如果你没有告诉 Guzzle 不要重定向,Guzzle 会自动的进行重定向,你可以使用 allow_redirects 请求参数来自定义重定向行为。
设置成 true 时将启用最大数量为5的重定向,这是默认设置。
设置成 false 来禁用重定向。
传入一个包含 max 键名的关联数组来声明最大重定向次数,提供可选的 strict 键名来声明是否使用严格的 RFC 标准重定向 (表示使用 POST 请求重定向 POST 请求 vs 大部分浏览器使用GET请求重定向 POST 请求)。
复制
$response = $client->request('GET', 'http://github.com');
echo $response->getStatusCode();
// 200
下面的列子表示重定向被禁止:
复制
$response = $client->request('GET', 'http://github.com', [
'allow_redirects' => false
]);
echo $response->getStatusCode();
异常
请求传输过程中出现的错误 Guzzle 将会抛出异常。
在发送网络错误(连接超时、DNS 错误等)时,将会抛出 GuzzleHttp\Exception\RequestException 异常。 该异常继承自 GuzzleHttp\Exception\TransferException ,捕获这个异常可以在传输请求过程中抛出异常。
复制
use GuzzleHttp\Exception\RequestException;
try {
$client->request('GET', 'https://github.com/_abc_123_404');
} catch (RequestException $e) {
echo $e->getRequest();
if ($e->hasResponse()) {
echo $e->getResponse();
}
}
GuzzleHttp\Exception\ConnectException 异常发生在网络错误时, 该异常继承自 GuzzleHttp\Exception\RequestException 。
如果 http_errors 请求参数设置成 true,在 400 级别的错误的时候将会抛出 GuzzleHttp\Exception\ClientException 异常, 该异常继承自 GuzzleHttp\Exception\BadResponseException GuzzleHttp\Exception\BadResponseException 继承自 GuzzleHttp\Exception\RequestException 。
复制
use GuzzleHttp\Exception\ClientException;
try {
$client->request('GET', 'https://github.com/_abc_123_404');
} catch (ClientException $e) {
echo $e->getRequest();
echo $e->getResponse();
}
如果 http_errors 请求参数设置成 true,在 500 级别的错误的时候将会抛出 GuzzleHttp\Exception\ServerException 异常。 该异常继承自 GuzzleHttp\Exception\BadResponseException 。
GuzzleHttp\Exception\TooManyRedirectsException 异常发生在重定向次数过多时, 该异常继承自 GuzzleHttp\Exception\RequestException 。
上述所有异常均继承自 GuzzleHttp\Exception\TransferException 。
环境变量
Guzzle 提供了一些可自定义的环境变量:
GUZZLE_CURL_SELECT_TIMEOUT
当在 Curl 处理器时使用 curl_multi_select() 控制了 curl_multi_* 需要使用到的持续时间, 有些系统实现 PHP 的 curl_multi_select() 存在问题,调用该函数时总是等待超时的最大值。
HTTP_PROXY
定义了使用 Http 协议发送请求时使用的代理。
HTTPS_PROXY
定义了使用 Https 协议发送请求时使用的代理。
标签:ComposerHTTPHTTP API