Guzzle例外を処理し、HTTP本文を取得する


122

サーバーが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応答の本文は返しません。応答本文を取得するにはどうすればよいですか?


1
この質問は、この質問に関連しているstackoverflow.com/questions/17658283/...あまりにも、いくつかの助けであるかもしれないと回答。
Trendfischer 2016年

回答:


84

Guzzle 3.x

ごとのドキュメントには、(適切な例外タイプキャッチすることができClientErrorResponseException4xxのエラーのために)、その呼び出しgetResponse()応答オブジェクトを取得する方法を、それから呼び出すgetBody()ことに:

use Guzzle\Http\Exception\ClientErrorResponseException;

...

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

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


232

Guzzle 6.x

docsによるとキャッチする必要のある例外タイプは次のとおりです。

  • 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();
}

12
私にとって$response->getBody()->getContents()は空の文字列を返します。次に、ドキュメントでこれに遭遇しまし\GuzzleHttp\Psr7\str($e->getResponse()) 応答をPsr7文字列としてキャストすると、適切にフォーマットされた完全なエラーメッセージが表示されます。
Andy Place、

3
PSR 7をちらりと見た後の@AndyPlace(これは、私がこの回答を書いたときにリンクしたドキュメントのセクションでは参照されていませんでしたが、現在はそうです)呼び出しPsr7\str()が異なる結果になる理由はすぐにはわかりませんに->getContents()。これを実証する最小限の例はありますか?これにより、これを理解し、おそらくこの回答を更新できますか?
Mark Amery 2016

24
'http_errors' => false例外のスローを無効にするGuzzleリクエストでオプションを渡すことができることに言及する価値があります。その後$response->getBody()、ステータスコードが何であっても本文を取得できます$response->getStatusCode()。必要に応じて、ステータスコードをテストできます。
2017

2
@AndyPlaceの$response->getBody()->getContents()場合、ある場合には空の文字列が返されますが、その理由はわかりません。しかし、を使用\GuzzleHttp\Psr7\str()すると、すべてのHTTP応答が文字列として返され、HTTP本体のみが返されます。ドキュメントで述べたように、ボディは文字列にキャストすることで使用できます。$stringBody = (string) $clientException->getResponse()->getBody();
AnthonyB 2017

1
これでうまくいきましたが、\GuzzleHttp\Exception\RequestException代わりに400ステータスコードを返すを取得していました。{$ request-> api( 'POST'、 'endpoint.json');を試してください。} catch(RequestException $ e){print_r($ e-> getResponse()-> getBody()-> getContents()); }
jpcaparas

54

上記の回答は適切ですが、ネットワークエラーをキャッチしません。Markが述べたように、BadResponseExceptionはClientExceptionおよびServerExceptionのスーパークラスにすぎません。ただし、RequestExceptionはBadResponseExceptionのスーパークラスでもあります。RequestExceptionは、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);
  }

}

あるJsonResponseがつがつ食うからのクラスは?
aexl

JsonResponsesymfonyのから来ている
CHAP

14

2019年現在、上記の回答とGuzzleのドキュメントから、例外を処理し、応答の本文、ステータスコード、メッセージ、およびその他の場合によっては貴重な応答項目を取得するために私が詳しく説明したものです。

try {
    /**
     * We use Guzzle to make an HTTP request somewhere in the
     * following theMethodMayThrowException().
     */
    $result = theMethodMayThrowException();
} catch (\GuzzleHttp\Exception\RequestException $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.
     * Just check the exception object has the response before.
     */
    if ($e->hasResponse()) {
        $response = $e->getResponse();
        var_dump($response->getStatusCode()); // HTTP status code;
        var_dump($response->getReasonPhrase()); // Response message;
        var_dump((string) $response->getBody()); // Body, normally it is JSON;
        var_dump(json_decode((string) $response->getBody())); // Body as the decoded JSON;
        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句、私たちは、継承チェーンPHPのルート例外クラスをキャッチ \Exceptionがつがつ食うカスタム例外は、それを拡張して。

このアプローチは、LaravelやAWS API PHP SDKのように内部でGuzzleを使用するユースケースに役立つため、本物のGuzzle例外をキャッチできません。

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

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

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

自分で直接Guzzleを呼び出す場合、キャッチするGuzzleHttp\Exception\RequestExceptionか、ユースケースの条件に関して例外ドキュメントで言及されている他のいずれかを呼び出すことができます。


1
あなたは、あなたのメソッドを呼び出すべきではありません$responseあなたがチェックしていない限り、例外を処理する場合、オブジェクトを$e->hasResponse()、そうでない場合$responseもありnull、任意のメソッドの呼び出しが致命的なエラーが発生します。
pwaring

@pwaring、真。まさにGuzzleの例外ドキュメントが言うように。回答を更新しました。ありがとうございました。
バレンタインShi

1
...しかし、これは修正後も問題があります。Guzzleの例外だけでなく、すべての例外をキャッチしていますが$e->hasResponse、結果はもちろん、Guzzle以外の例外には存在しないメソッドを呼び出しています。したがって、Guzzle以外の例外をから発生させるとtheMethodMayThrowException()、このコードはそれをキャッチし、存在しないメソッドを呼び出して、存在しないメソッドが原因でクラッシュし、エラーの真の原因を効果的に隠します。これを回避GuzzleHttp\Exception\RequestExceptionするのではなく、キャッチすることをお勧めしExceptionます。
マークアメリー

1
@MarkAmery、あなたの主張は完全に有効です。ありがとうございました。回答本文を更新しました。
バレンタイン市

1
@JaberAlNahian聞いてうれしい:)それは私の意図でした。常に歓迎。
バレンタイン市

4

置けば'http_errors' => falseがつがつ食う要求オプションでGETの4xxまたは5xxのエラーながら、それはこのように、スロー例外を停止します:$client->get(url, ['http_errors' => false])。次に、応答を解析します。問題があるかどうかは関係ありません。詳細については、応答に含ま れます。


この質問は、エラー例外の停止を要求しないエラー処理についてです
Dlk
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.