web-dev-qa-db-ja.com

Guzzle例外を処理し、HTTPボディを取得する

サーバーが4xxおよび5xxステータスコードを返したときのGuzzleからのエラーを処理したいと思います。私はこのようなリクエストをします:

$client = $this->getGuzzleClient();
$request = $client->post($url, $headers, $value);
try {
    $response = $request->send();
    return $response->getBody();
} catch (\Exception $e) {
    // How can I get the response body?
}

$e->getMessageは、HTTP応答の本文ではなくコード情報を返します。応答本文を取得するにはどうすればよいですか?

96
domos

Guzzle 3.x

ドキュメント ごとに、適切な例外タイプ(4xxエラーの場合はClientErrorResponseException)をキャッチし、そのgetResponse()メソッドを呼び出して応答オブジェクトを取得し、その上でgetBody()を呼び出します。

use Guzzle\Http\Exception\ClientErrorResponseException;

...

try {
    $response = $request->send();
} catch (ClientErrorResponseException $exception) {
    $responseBody = $exception->getResponse()->getBody(true);
}

truegetBody 関数に渡すと、応答本文を文字列として取得することを示します。それ以外の場合は、Guzzle\Http\EntityBodyクラスのインスタンスとして取得します。

62
sebbo

Guzzle 6.x

ドキュメント ごとに、キャッチする必要がある例外タイプは次のとおりです。

  • GuzzleHttp\Exception\ClientException 400レベルのエラーの場合
  • GuzzleHttp\Exception\ServerException 500レベルのエラーの場合
  • 両方のGuzzleHttp\Exception\BadResponseException(スーパークラスです)

そのため、このようなエラーを処理するコードは次のようになります。

$client = new GuzzleHttp\Client;
try {
    $client->get('http://google.com/nosuchpage');    
}
catch (GuzzleHttp\Exception\ClientException $e) {
    $response = $e->getResponse();
    $responseBodyAsString = $response->getBody()->getContents();
}
191
Mark Amery

上記の回答は良好ですが、ネットワークエラーは処理しませんが、Markが述べたように、BadResponseExceptionはClientExceptionとServerExceptionの単なるスーパークラスです。ただし、RequestExceptionはBadRequestExceptionのスーパークラスでもあります。これにより、400および500エラーだけでなく、ネットワークエラーもキャッチされます。以下のページをリクエストしたが、ネットワークが再生中であり、キャッチがBadResponseExceptionを予期しているとしましょう。アプリケーションはエラーをスローします。

この場合、RequestExceptionを予期して応答を確認する方が適切です。

try {
  $client->get('http://123123123.com')
} catch (RequestException $e) {

  // If there are network errors, we need to ensure the application doesn't crash.
  // if $e->hasResponse is not null we can attempt to get the message
  // Otherwise, we'll just pass a network unavailable message.
  if ($e->hasResponse()) {
    $exception = (string) $e->getResponse()->getBody();
    $exception = json_decode($exception);
    return new JsonResponse($exception, $e->getCode());
  } else {
    return new JsonResponse($e->getMessage(), 503);
  }

}
42
chap

2019年の時点で、上記の回答と Guzzle docs から詳しく説明し、例外を処理し、応答本文、ステータスコード、メッセージ、およびその他の重要な応答項目を取得します。

try {
    /**
     * We use Guzzle to make an HTTP request somewhere in the
     * following theMethodMayThrowException().
     */
    $result = theMethodMayThorwException();
} catch (\Exception $e) {
    /**
     * Here we actually catch the instance of GuzzleHttp\Psr7\Response
     * (find it in ./vendor/guzzlehttp/psr7/src/Response.php) with all
     * its own and its 'Message' trait's methods. See more explanations below.
     *
     * So you can have: HTTP status code, message, headers and body.
     */
    $response = $e->getResponse();
    var_dump($response->getStatusCode()); // HTTP status code
    var_dump($response->getReasonPhrase()); // Message
    var_dump((string) $response->getBody()); // Body
    var_dump($response->getHeaders()); // Headers array
    var_dump($response->hasHeader('Content-Type')); // Is the header presented
    var_dump($response->getHeader('Content-Type')[0]); // Concrete header value
}
// process $result etc. ...

出来上がり。応答の情報は、便利​​に分離されたアイテムで取得します。

サイドノート:

catch句を使用すると、Guzzleカスタム例外が拡張するため、継承チェーンPHPルート例外クラス\Exceptionをキャッチします。

このアプローチは、GuzzleがLaravelまたはAWS API PHP SDKのように内部で使用されるユースケースに役立ち、真のGuzzle例外をキャッチできません。

この場合、例外クラスはGuzzleのドキュメントに記載されているものではない可能性があります(例:Guzzleのルート例外としてGuzzleHttp\Exception\RequestException)。

そのため、代わりに\Exceptionをキャッチする必要がありますが、それは依然としてGuzzle例外クラスインスタンスであることに注意してください。

注意して使用しますが。これらのラッパーにより、Guzzle $e->getResponse()オブジェクトの真のメソッドが利用できなくなる場合があります。この場合、Guzzle $responseのメソッドを使用する代わりに、ラッパーの実際の例外ソースコードを調べて、ステータス、メッセージなどを取得する方法を見つける必要があります。

Guzzleを直接自分で呼び出す場合、ユースケース条件に関してGuzzleHttp\Exception\RequestExceptionまたは their exceptions docs で言及されている他のいずれかをキャッチできます。

3
bob-12345