はじめに
LaravelでHTTPリクエストを投げたかったのでGuzzleを使ってみました。
以前ですとPEARのHTTP_Request2を使っていましたが、あまり最近使われていないようなので新しいパッケージを使ってみました。
HTTP_Request2は長年使ってまして、使いやすくて好きです。cURLも悪くはないのですが…。
Laravelで使いましたが、もちろん生のPHPでも使えます。
Laravelのラッパー
Laravel 7系ではGuzzleラッパーが提供されているようです。
例
$response = Http::post('http://test.com/users', [
'name' => 'Steve',
'role' => 'Network Administrator',
]);
@macky4 さんありがとうございます。
Laravelだとラッパーのおかけでもっと楽に書けますよ!
https://readouble.com/laravel/7.x/ja/http-client.html
インストール
今回はLaravelで使ってみました。生のPHPでもOKです。
$ laravel new hogeproject
$ cd hogeproject
$ composer require guzzlehttp/guzzle
Using version ^6.2 for guzzlehttp/guzzle
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
コントローラの作成
$ php artisan make:controller HogeController
リクエストの作成
$ php artisan make:controller HogeController
Route::get('/basic_request', 'HogeController@basic_request');
Route::get('/with_headers', 'HogeController@with_headers');
GET
GETリクエスト
public function basic_request() {
$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );
$path = '/index.html';
$response = $client->request( 'GET', $path,
[
'allow_redirects' => true,
] );
$response_body = (string) $response->getBody();
echo $response_body;
}
ステータスコード取得
public function get_http_status_code() {
$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );
$path = '/index.html';
$response = $client->request( 'GET', $path,
[
'allow_redirects' => true,
] );
$response_body = (string) $response->getStatusCode();
echo $response_body;
}
JSONで送る
$response = $client->request('PUT', '/put', ['json' => ['foo' => 'bar']]);
request
のオプション引数にjson
で配列を渡すと良い感じにしてくれます。
(おそらく)json_encode()
, Conent-Type: application/json
の指定を行ってくれます。
http://docs.guzzlephp.org/en/latest/request-options.html#json
リクエストヘッダー指定
リファラーなどのリクエストヘッダーを指定する場合には配列を渡します。
public function with_headers() {
$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );
$path = '/index.html';
$headers = [
'Origin' => 'http://www.example.com',
'Accept-Encoding' => 'gzip, deflate, br',
'Accept-Language' => 'ja,en-US;q=0.8,en;q=0.6',
'Upgrade-Insecure-Requests' => '1',
'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36',
'Content-Type' => 'application/x-www-form-urlencoded',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Cache-Control' => 'max-age=0',
'Referer' => 'http://www.example.com',
'Connection' => 'keep-alive'
];
$response = $client->request( 'GET', $path,
[
'allow_redirects' => true,
'headers' => $headers,
//'form_params' => $form_params,
] );
$response_body = (string) $response->getBody();
echo $response_body;
}
GETでクエリストリングを指定
query
に配列を指定するとクエリストリングを指定できるようです。
public function get_with_params() {
$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );
$path = '/index.html';
$dev_null = $client->get($path,
[
'query' => ['foo' => 'bar'],
'on_stats' => function (\GuzzleHttp\TransferStats $stats) use (&$url) {
$url = $stats->getEffectiveUri();
}
] )->getBody()->getContents();
echo $url;
}
404を許容する書き方
404の場合には例外を投げられてしまいます。
この例外を回避する2つの方法です。
まずはエラーメッセージについてです。
[GuzzleHttp\Exception\ClientException]
Client error: `GET http://www.l2tp.org/index.html` resulted in a `404 Not Foun
d` response:
<!DOCTYPE html>
<html lang="ja" class="no-js no-svg">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width (truncated...)
http_errorsをfalseにする
@bootjp さんに教えてもらいました。ありがとうございます!
リクエストを投げる際にhttp_errors
というオプションをfalse
にすると例外を投げられないようです。
$client->request('GET', '/status/500');
// Throws a GuzzleHttp\Exception\ServerException
$res = $client->request('GET', '/status/500', ['http_errors' => false]);
echo $res->getStatusCode();
// 500
false
に設定すると400番台、500番台などのHTTPエラーを無効化します。デフォルトでは例外が飛ばされます。
Set to false to disable throwing exceptions on an HTTP protocol errors (i.e., 4xx and 5xx responses). Exceptions are thrown by default when HTTP protocol errors are encountered.
例外を拾う
もう一つの方法はClientExceptionで例外を拾います。
投げられる例外のClientExceptionはResponseと同じような使い方ができます。
try {
$client->request('GET', 'https://github.com/_abc_123_404');
} catch (ClientException $e) {
echo Psr7\str($e->getRequest());
echo Psr7\str($e->getResponse());
}
もしくはレスポンスを使う場合、getResponseを受けて渡すと良いようです。
try {
$client->request('GET', 'https://github.com/_abc_123_404');
} catch (ClientException $e) {
$response = $e->getResponse();
}
echo $response->getStatusCode();
リクエストを確認する
デバッグを行うときにそもそも思った通りのリクエストが投げれているか、ということを確認したい場合があります。
そういう場合の確認方法です。
リクエストしたbodyの確認
上記とは変わってbodyの確認を行います。
どういったリクエストが送られているか確認するときに使います。
public function send_request_with_dump() {
$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );
$path = '/index.html';
$stack = HandlerStack::create();
// my middleware
$stack->push(Middleware::mapRequest(function (RequestInterface $request) use (&$contentsRequest) {
$contentsRequest = (string) $request->getBody();
var_dump($contentsRequest);
return $request;
}));
$dev_null = $client->request( 'GET', $path,
[
'handler' => $stack,
] )->getBody()->getContents();
echo $url;
}
How do I get the body of SENT data with Guzzle PHP?
http://stackoverflow.com/a/34911017/2405335
ミドルウェアの機構を使ってリクエスト時に関数を実行します。戻り値でのとり方はわからなかったので参考先通りにvar_dump()
しています。
リクエストヘッダの確認
リクエストしたヘッダの確認です。レスポンスヘッダじゃなくてリクエストしたヘッダです。
$YourGuzzleclient=new Client();
$YourGuzzleclient->request('POST', '{Your url}',
['debug'=>true,'otheroptions'=>array()]
);
リクエストしたURLの確認
ちょっと書き方が新しいですね。on_stats
にTransferStatus
を受けるクロージャを渡すと、その中でurlを取得できるようです。
use
と参照渡しで外側でも参照できます。JavaScriptっぽいですね。
PHPの内部で変数などを実行した際にちゃんと送れているか、というデバッグに使いました。
public function get_requested_url() {
$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );
$path = '/index.html';
$dev_null = $client->request( 'GET', $path,
[
'on_stats' => function (\GuzzleHttp\TransferStats $stats) use (&$url) {
$url = $stats->getEffectiveUri();
}
] )->getBody()->getContents();
echo $url; // http://example.com/index.html
}
参考: How to read the response effective URL in Guzzle ~6.0
並列アクセス
Promiseを使った並列アクセスが可能です。
クロージャを用意し、new Pool()
に$client
とRequestを行う関数を渡します。
<?php
require_once 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
$client = new Client();
$requests = function ($urls) {
for ($i = 0; $i < count($urls); $i++) {
yield new Request('GET', $urls[$i]);
}
};
$urls = [
'http://example.com',
'http://example.com',
'http://example.com',
'http://example.com',
];
$pool = new Pool($client, $requests($urls), [
'concurrency' => 5,
'fulfilled' => function (Response $response, $index) {
// var_dump($response->getHeader('Server'));
// this is delivered each successful response
},
'rejected' => function (RequestException $reason, $index) {
// this is delivered each failed request
},
]);
// Initiate the transfers and create a promise
$promise = $pool->promise();
// Force the pool of requests to complete.
$promise->wait();
参考
[Using GuzzleHttp with Laravel]
(https://medium.com/laravel-5-the-right-way/using-guzzlehttp-with-laravel-1dbea1f633da)
Guzzle で Twitter REST API を叩く