web-dev-qa-db-fra.com

Attraper des exceptions de Guzzle

J'essaie de détecter les exceptions d'un ensemble de tests que j'effectue sur une API que je développe et que j'utilise Guzzle pour utiliser les méthodes de l'API. J'ai les tests encapsulés dans un bloc try/catch mais il continue à générer des erreurs d'exception non gérées. L'ajout d'un écouteur d'événement tel que décrit dans leur documentation ne semble rien faire. Je dois pouvoir récupérer les réponses qui ont des codes HTTP de 500, 401, 400, en fait, tout ce qui n'est pas 200, car le système définira le code le plus approprié en fonction du résultat de l'appel s'il ne fonctionne pas. .

Exemple de code actuel

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;

    }

Même avec le bloc catch spécifique pour le type d'exception levée, je récupère toujours

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

et toute exécution sur la page s'arrête, comme vous le souhaitiez. L'ajout de la capture BadResponseException m'a permis d'attraper 404 correctement, mais cela ne semble pas fonctionner pour 500 ou 401 réponses. Quelqu'un peut-il suggérer où je me trompe s'il vous plaît.

65
Eric

Si l'exception est lancée dans ce bloc try, alors, dans le pire des cas, le scénario Exception devrait intercepter des éléments non capturés.

Considérez que la première partie du test renvoie l’exception et encapsulez-la également dans le bloc try.

13
user2584140

Selon votre projet, il peut être nécessaire de désactiver les exceptions pour le masque. Parfois, les règles de codage interdisent les exceptions pour le contrôle de flux. Vous pouvez désactiver les exceptions pour Guzzle comme ceci:

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

Cela ne désactive pas les exceptions curl pour quelque chose comme les délais d'attente, mais vous pouvez maintenant obtenir facilement chaque code de statut:

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

Pour vérifier, si vous avez un code valide, vous pouvez utiliser quelque chose comme ceci:

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

... ou mieux gérer tous les codes attendus:

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...");
}

Pour Guzzle 5.

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

Merci à @mika

Pour Guzzle 6

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

Pour attraper les erreurs de Guzzle, vous pouvez faire quelque chose comme ceci:

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

... mais pour pouvoir "vous connecter" ou "renvoyer" votre demande, essayez quelque chose comme ceci:

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

});

... ou si vous voulez "arrêter la propagation d'événements", vous pouvez remplacer l'écouteur d'événements (avec une priorité supérieure à -255) et simplement arrêter la propagation d'événements.

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

c’est une bonne idée de prévenir les erreurs de type:

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

dans votre application.

45
Dado

Dans mon cas, je jetais Exception sur un fichier de noms, donc php a essayé d'attraper My\Namespace\Exception, Donc il n'a attrapé aucune exception.

Cela vaut la peine de vérifier si catch (Exception $e) trouve la bonne classe Exception.

Essayez simplement catch (\Exception $e) (avec ce \ Ici) et voyez si cela fonctionne.

29
dmmd

Vous devez ajouter un paramètre supplémentaire avec http_errors => false

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

Ancienne question, mais Guzzle ajoute la réponse dans l'objet exception. Donc, un simple essai sur GuzzleHttp\Exception\ClientException puis utiliser getResponse sur cette exception pour voir quelle erreur de niveau 400 et continuer à partir de là.

5
Carson Reinke

J'attrapais GuzzleHttp\Exception\BadResponseException comme @dado le suggère. Mais un jour j'ai GuzzleHttp\Exception\ConnectException lorsque DNS pour le domaine n’était pas disponible. Donc, ma suggestion est - attraper GuzzleHttp\Exception\ConnectException pour éviter les erreurs DNS également.

2
Ivan Yarych