web-dev-qa-db-ja.com

Guzzleから例外をキャッチする

開発中のAPIで実行している一連のテストから例外をキャッチしようとしています。APIメソッドを使用するためにGuzzleを使用しています。テストをtry/catchブロックにラップしましたが、未処理の例外エラーが引き続き発生しています。ドキュメントに記載されているイベントリスナーを追加しても、何も実行されないようです。 500、401、400のHTTPコードを持つ応答を取得できるようにする必要があります。実際には、システムが機能しなかった場合、システムは呼び出しの結果に基づいて最も適切なコードを設定するため、200以外のすべて。

現在のコード例

foreach($tests as $test){

        $client = new Client($api_url);
        $client->getEventDispatcher()->addListener('request.error', function(Event $event) {        

            if ($event['response']->getStatusCode() == 401) {
                $newResponse = new Response($event['response']->getStatusCode());
                $event['response'] = $newResponse;
                $event->stopPropagation();
            }            
        });

        try {

            $client->setDefaultOption('query', $query_string);
            $request = $client->get($api_version . $test['method'], array(), isset($test['query'])?$test['query']:array());


          // Do something with Guzzle.
            $response = $request->send();   
            displayTest($request, $response);
        }
        catch (Guzzle\Http\Exception\ClientErrorResponseException $e) {

            $req = $e->getRequest();
            $resp =$e->getResponse();
            displayTest($req,$resp);
        }
        catch (Guzzle\Http\Exception\ServerErrorResponseException $e) {

            $req = $e->getRequest();
            $resp =$e->getResponse();
            displayTest($req,$resp);
        }
        catch (Guzzle\Http\Exception\BadResponseException $e) {

            $req = $e->getRequest();
            $resp =$e->getResponse();
            displayTest($req,$resp);
        }
        catch( Exception $e){
            echo "AGH!";
        }

        unset($client);
        $client=null;

    }

スローされた例外タイプの特定のcatchブロックを使用しても、まだ戻ってきています

Fatal error: Uncaught exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message 'Client error response [status code] 401 [reason phrase] Unauthorized [url]

予想どおり、ページ上のすべての実行が停止します。 BadResponseExceptionキャッチの追加により、404を正しくキャッチできましたが、これは500または401の応答では機能しないようです。誰でも私が間違っているところを教えてください。

65
Eric

そのtryブロックで例外がスローされている場合、最悪の場合、シナリオExceptionはキャッチされていないものをキャッチします。

テストの最初の部分が例外をスローすることを考慮し、それをtryブロックでラップします。

13
user2584140

プロジェクトによっては、ガズルの例外を無効にする必要がある場合があります。コーディング規則では、フロー制御の例外が許可されない場合があります。例外を無効にすることができますGuzzle 3の場合このように:

$client = new \Guzzle\Http\Client($httpBase, array(
  'request.options' => array(
     'exceptions' => false,
   )
));

これにより、タイムアウトなどのカール例外は無効になりませんが、すべてのステータスコードを簡単に取得できます。

$request = $client->get($uri);
$response = $request->send();
$statuscode = $response->getStatusCode();

有効なコードを取得したかどうかを確認するには、次のようなものを使用できます。

if ($statuscode > 300) {
  // Do some error handling
}

...または、予想されるすべてのコードを処理する:

if (200 === $statuscode) {
  // Do something
}
elseif (304 === $statuscode) {
  // Nothing to do
}
elseif (404 === $statuscode) {
  // Clean up DB or something like this
}
else {
  throw new MyException("Invalid response from api...");
}

Guzzle 5.3の場合

$client = new \GuzzleHttp\Client(['defaults' => [ 'exceptions' => false ]] );

@mikaに感謝

Guzzle 6の場合

$client = new \GuzzleHttp\Client(['http_errors' => false]);
113
Trendfischer

Guzzleエラーをキャッチするには、次のようなことができます。

try {
    $response = $client->get('/not_found.xml')->send();
} catch (Guzzle\Http\Exception\BadResponseException $e) {
    echo 'Uh oh! ' . $e->getMessage();
}

...しかし、リクエストを「記録」または「再送」できるようにするには、次のようなものを試してください:

// Add custom error handling to any request created by this client
$client->getEventDispatcher()->addListener(
    'request.error', 
    function(Event $event) {

        //write log here ...

        if ($event['response']->getStatusCode() == 401) {

            // create new token and resend your request...
            $newRequest = $event['request']->clone();
            $newRequest->setHeader('X-Auth-Header', MyApplication::getNewAuthToken());
            $newResponse = $newRequest->send();

            // Set the response object of the request without firing more events
            $event['response'] = $newResponse;

            // You can also change the response and fire the normal chain of
            // events by calling $event['request']->setResponse($newResponse);

            // Stop other events from firing when you override 401 responses
            $event->stopPropagation();
        }

});

...または、「イベントの伝播を停止する」場合は、イベントリスナーをオーバーライドし(-255より高い優先度で)、イベントの伝播を停止することができます。

$client->getEventDispatcher()->addListener('request.error', function(Event $event) {
if ($event['response']->getStatusCode() != 200) {
        // Stop other events from firing when you get stytus-code != 200
        $event->stopPropagation();
    }
});

次のようなガズルエラーを防ぐのは良い考えです。

request.CRITICAL: Uncaught PHP Exception Guzzle\Http\Exception\ClientErrorResponseException: "Client error response

アプリケーションで。

45
Dado

私の場合、名前空間ファイルにExceptionを投げていたので、phpはMy\Namespace\Exceptionをキャッチしようとしたため、例外はまったくキャッチしませんでした。

catch (Exception $e)が正しいExceptionクラスを見つけているかどうかを確認する価値があります。

catch (\Exception $e)(その\がある)を試して、それが機能するかどうかを確認してください。

29
dmmd

Http_errors => falseのパラメーターを追加する必要があります

$request = $client->get($url, ['http_errors' => false]);
10
andr3s2

古い質問ですが、Guzzleは例外オブジェクト内に応答を追加します。したがって、GuzzleHttp\Exception\ClientExceptionで単純なtry-catchを実行し、その例外でgetResponseを使用して、400レベルのエラーを確認し、そこから続行します。

5
Carson Reinke

@dadoが示唆しているように、GuzzleHttp\Exception\BadResponseExceptionをキャッチしていました。しかし、ある日、ドメインのDNSが利用できないときにGuzzleHttp\Exception\ConnectExceptionを受け取りました。したがって、私の提案は-GuzzleHttp\Exception\ConnectExceptionをキャッチして、DNSエラーについても安全であるようにすることです。

2
Ivan Yarych