1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Symfony ComponentAdvent Calendar 2022

Day 17

HTTP通信クライアント、"HttpClient"

Last updated at Posted at 2022-12-16

Symfony Component Advent Calendar 2022の17日目の記事です。

最初に

SymfonyはPHPのフレームワークのひとつです。しかし、公式サイトの説明文には

Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community — all working together in harmony.
(SymfonyはPHPコンポーネントのセットで、Webアプリケーションフレームワークで、哲学、そしてコミュニティです。それらがハーモニーを奏でながら動作しています。)

と書かれている通り、PHPコンポーネントのセットで、たくさんのコンポーネントを提供しており、それらを組み合わせてひとつのフレームワークとして動作しています。Symfonyのコンポーネントは、Symfony上だけで動作するのではなく、他のPHPフレームワークやアプリケーションでも動作している強力なものが揃っています。

今回はそれらの中から、役立ちそうなもの・お薦めしたいものを紹介していきたいと思います。

※記事内ではautoloadのインポートは省略します。

HTTP通信クライアント、"HttpClient"

HttpClientは、その名の通りHTTP通信のクライアントを扱うコンポーネントです。通常のHTTP通信に加え、SSRF対策、HTTP/2通信、ストリーム通信などに対応しています。

インストール

composer require symfony/http-client

HTTP通信する

HttpClientオブジェクトを使って通信を行います。Symfonyの場合は、いつも通りオートワイヤリングでDIできます。

GET



use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\HttpClient;

// Symfony以外の場合
$client = HttpClient::create();
$response = $client->request('GET', 'https://qiita.com/api/v2/items?query=Symfony', [
    'headers' => [
        'Authorization' => 'Bear: ......'
    ],
]);

// ステータスコード
$statusCode = $response->getStatusCode();
// レスポンスヘッダ
$headers = $response->getHeaders();
// レスポンスを文字列で
$response->getContent();
// レスポンスを配列で
$response->toArray();

// Symfonyの場合
class SomeService
{
    public function __construct(private readonly HttpClientInterface $client)
    {
    }
    
    public function someMethod()
    {
        $response = $client->request('GET', 'https://qiita.com/api/v2/items?query=Symfony', [
            'headers' => [
                'Authorization' => 'Bear: ......'
            ],
        ]);
        
        // 以下同様
    }
}
POST

POSTデータを送る場合は、request()メソッドの第3引数にbodyというキーで設定します。JSONを送信する場合はbodyではなく、jsonを使うと、Content-Type: application/jsonを勝手にヘッダに追加してくれます。


$client = HttpClient::create();
$response = $client->request('POST', 'https://qiita.com/api/v2/items', [
    'body' => '{"titie": "Symfonyすき"}', // 生データの場合
    'body' => ['title' => 'Symfonyすき'], // 配列の場合
    'json' => ['title' => 'Symfonyすき'], // JSONで送る場合
]);

// レスポンスはGETと同じように扱えます

SSRF(Server-side Request forgery)対策

HttpClientでは、SSRF対策として、NoPrivateNetworkHttpClientクラスが用意されています。

NoPrivateNetworkHttpClientを使うと、内部サーバへのHTTP通信ができないようになります。


$url = $request->request->get('your_url');

try {
    $client = new NoPrivateNetworkHttpClient(HttpClient::create());
    $response = $client->request('GET', $url);
    ...
} catch (TransportException $e) {
    // 内部サーバへのHTTP通信の場合、TransportExceptionを吐きます。
    ...
}

HTTP/2対応

以下の条件をクリアしていれば自動的にHTTP/2通信となります。

  • httpsにアクセス
  • libcurl 7.36以上 もしくは、amphp/http-client 4.2以上インストール済み

ストリーム通信対応

アクセス先がストリーミング配信の場合、stream()メソッドを使うことで対応可能です。

$response = $client->request('GET', $url);

foreach ($client->stream($response) as $chunk) {
    print_r($chunk->getContent()); // ストリーム配信されたデータを受け取るたびに出力
}

また、非同期で複数のリクエストも受け取ることができます。

$responses = [];
$images = [
    'a.png',
    'b.png',
    'c.png',
];
foreach($images as $image) {
    $url = sprintf("https://some-domain/%s", $image);
    $responses[] = $client->request('GET', $url);
}

foreach ($client->stream($responses) as $response => $chunk) {
    // $responseはそれぞれのレスポンスオブジェクト
    // $chunkはそれぞれの配信されたデータ
}

まとめ

今回はHttpClientについて紹介しました。PHPでHTTP通信といえばGuzzleですが、Symfony公式が用意してくれてるので、せっかくならこちらを使っていきたいところです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?