Help us understand the problem. What is going on with this article?

Guzzleでの非同期リクエスト

More than 1 year has passed since last update.

環境

PHP5.6
Guzzle6.3

公式ドキュメント:
http://docs.guzzlephp.org/en/stable/index.html

guzzle インストール

composerでインストールします。

composer require guzzlehttp/guzzle

簡易版非同期リクエスト

require_once(dirname(__FILE__) . '/vendor/autoload.php');
use GuzzleHttp\Client;

$client = new Client();
//$client = new \GuzzleHttp\Client(['cookies' => true]); //クッキーを利用したい場合
//$client = new \GuzzleHttp\Client(['debug' => true]); //通信内容をデバッグしたい場合

$promises[] = $client->requestAsync('GET', 'https://sample.com/1.html');
$promises[] = $client->requestAsync('GET', 'https://sample.com/2.html');
$promises[] = $client->requestAsync('GET', 'https://sample.com/3.html');
$promises[] = $client->requestAsync('GET', 'https://sample.com/4.html');
$promises[] = $client->requestAsync('GET', 'https://sample.com/5.html');

$responses = \GuzzleHttp\Promise\all($promises)->wait();

$result = [];
foreach ($responses as $response) {
    $result[] = [
      'html'             => $response->getBody()->getContents(),
      'status_code'      => $response->getStatusCode(), //ステータスコード
      'reason_phrase'    => $response->getReasonPhrase(), //
      'protocol_version' => $response->getProtocolVersion(),
      'response_header'  => $response->getHeaders()
    ];
}

var_dump($result);
  • 5リクエストを非同期リクエストします
  • 非同期なので、$resultに入ってくるレスポンスは順不同
  • 非同期でPOSTしたい場合の例は下記です。(フォーム送信したいデータがある・ヘッダ指定したいケース)
$config = [
  //ヘッダ指定
  'headers' => [
      'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
      'Accept-Encoding' => 'gzip, deflate, br',
      'Accept-Language' => 'ja,en-US;q=0.9,en;q=0.8',
      'Cache-Control' => 'max-age=0',
      'Connection' => 'keep-alive',
      'Host' => 'sample.com',
      'Upgrade-Insecure-Requests' => 1,
      'User-Agent' => 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'
  ],
  //パラメータ指定
  'form_params' => [
    'email' => 'test@sample.com',
    'name'  => 'test'
  ]
];

$promises[] = $client->requestAsync('POST', 'https://sample.com/aaa.html', $config);
$response = \GuzzleHttp\Promise\all($promises)->wait();

メモリ節約版非同期リクエスト

<?php
    require_once(dirname(__FILE__) . '/vendor/autoload.php');

    use GuzzleHttp\Pool;
    use GuzzleHttp\Client;
    use GuzzleHttp\Psr7\Request;

    $client = new Client();

    $urlList = [
      'https://sample.com/1.html',
      'https://sample.com/2.html',
      'https://sample.com/3.html',
      'https://sample.com/4.html',
      'https://sample.com/5.html',
      'https://sample.com/6.html',
      'https://sample.com/7.html',
      'https://sample.com/8.html',
      'https://sample.com/9.html',
      'https://sample.com/10.html'
    ];

    $requests = function ($urlList) use ($client) {
        foreach ($urlList as $url) {
            yield function() use ($client, $url) {
                return $client->requestAsync('GET', $url);
            };
        }
    };

    $contents = [];

    $pool = new Pool($client, $requests($urlList), [
        'concurrency' => 10,
        'fulfilled' => function ($response, $index) use ($urlList, &$contents) {
            $contents[$urlList[$index]] = [
              'html'             => $response->getBody()->getContents(),
              'status_code'      => $response->getStatusCode(),
              'response_header'  => $response->getHeaders()
            ];
        },
        'rejected' => function ($reason, $index) use ($urlList, &$contents) {
            // this is delivered each failed request
            $contents[$urlList[$index]] = [
              'html'   => '',
              'reason' => $reason
            ];
        },
    ]);

    $promise = $pool->promise();
    $promise->wait();

    var_dump($contents);
  • 簡易版で大量に非同期リクエストした場合、promiseオブジェクトにリクエスト数分状態を保持してしまうのでメモリオーバーする事がある
  • ジェネレータを使うと実際に必要になる(Poolで順次実行される時)までリクエストが実行されずメモリを消費しない
  • レスポンスの$indexで、どのリクエストのレスポンスか把握できる

参考:
https://speakerdeck.com/suzuki/guzzle-promisewoshi-tuta-fei-tong-qi-chu-li-niyoruapikorufalsegao-su-hua
https://mike-neko.github.io/blog/guzzle/

bz0
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away