107 votes

Capture des exceptions à partir de Guzzle

J'essaie d'attraper les exceptions d'un ensemble de tests que j'exécute sur une API que je développe et j'utilise Guzzle pour consommer les méthodes de l'API. J'ai placé les tests dans un bloc try/catch, mais les erreurs d'exception non gérées sont toujours présentes. L'ajout d'un écouteur d'événements tel que décrit dans la documentation ne semble rien faire. J'ai besoin de 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 de capture spécifique pour le type d'exception lancé, j'obtiens toujours le résultat suivant

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 on peut s'y attendre. L'ajout de la capture BadResponseException m'a permis d'attraper correctement les 404, mais cela ne semble pas fonctionner pour les réponses 500 ou 401. Quelqu'un peut-il me dire où je me trompe, s'il vous plaît ?

170voto

Trendfischer Points 319

En fonction de votre projet, la désactivation des exceptions pour guzzle peut être nécessaire. Parfois, les règles de codage interdisent les exceptions pour le contrôle de flux. Vous pouvez désactiver les exceptions pour Guzzle 3 comme ça :

$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 maintenant vous pouvez obtenir chaque code d'état facilement :

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

Pour vérifier, si vous avez obtenu 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.3

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

Merci à @mika

Pour Guzzle 6

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

49voto

Dado Points 449

Pour détecter les erreurs de Guzzle, vous pouvez procéder comme suit :

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

... mais, pour pouvoir "enregistrer" 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 des événements", vous pouvez remplacer l'écouteur d'événements (avec une priorité plus élevée que -255) et simplement arrêter la propagation des é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 pour éviter les erreurs de type "guzzle" :

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

dans votre application.

39voto

dmmd Points 815

Dans mon cas, je lançais Exception sur un fichier avec un espace de nom, donc php a essayé d'attraper My\Namespace\Exception et donc de ne pas attraper d'exceptions du tout.

Il convient de vérifier si catch (Exception $e) est de trouver le bon Exception classe.

Essayez juste catch (\Exception $e) (avec cette \ là) et voir si cela fonctionne.

21voto

Si l'exception est lancée dans cette try bloquer alors dans le pire des cas Exception devrait attraper tout ce qui n'est pas attrapé.

Considérez que la première partie du test consiste à lancer l'exception et intégrez-la dans la balise try également.

15voto

andr3s2 Points 218

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X