docs debug php api functional-testing guzzle

php - debug - Capturando excepciones de Guzzle



install guzzle (8)

Estoy tratando de detectar excepciones de un conjunto de pruebas que estoy ejecutando en una API que estoy desarrollando y estoy usando Guzzle para consumir los métodos API. Tengo las pruebas envueltas en un bloque try / catch, pero aún arroja errores de excepción no controlados. Agregar un detector de eventos como se describe en sus documentos no parece hacer nada. Necesito poder recuperar las respuestas que tienen códigos HTTP de 500, 401, 400, de hecho, cualquier cosa que no sea 200 ya que el sistema establecerá el código más apropiado en función del resultado de la llamada si no funcionó .

Ejemplo de código actual

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; }

Incluso con el bloque catch específico para el tipo de excepción lanzada todavía estoy volviendo

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

y toda la ejecución en la página se detiene, como era de esperar. La adición de la captura BadResponseException me permitió detectar los 404 correctamente, pero parece que esto no funciona para 500 o 401 respuestas. ¿Alguien puede sugerirme dónde estoy yendo mal, por favor?


Dependiendo de su proyecto, la desactivación de excepciones para guzzle podría ser necesaria. A veces, las reglas de codificación no permiten excepciones para el control de flujo. Puede desactivar excepciones para Guzzle 3 de esta manera:

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

Esto no deshabilita las excepciones curl para algo así como tiempos de espera, pero ahora puede obtener todos los códigos de estado fácilmente:

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

Para verificar, si tiene un código válido, puede usar algo como esto:

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

... o manejar mejor todos los códigos esperados:

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

Para Guzzle 5.3

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

Gracias a @mika

Para Guzzle 6

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


En mi caso, estaba lanzando Exception en un archivo de espacio de nombres, por lo que php intentó capturar My/Namespace/Exception por lo que no detectó ninguna excepción.

Vale la pena verificar si la catch (Exception $e) está encontrando la clase de Exception correcta.

Simplemente intente catch (/Exception $e) (with that / there) y vea si funciona.


Necesita agregar un parámetro extra con http_errors => false

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


Para detectar los errores de Guzzle puedes hacer algo como esto:

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

... pero, para poder "registrar" o "volver a enviar" su solicitud, pruebe algo como esto:

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

... o si desea "detener la propagación de eventos" puede anular el detector de eventos (con una prioridad mayor que -255) y simplemente detener la propagación de eventos.

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

esa es una buena idea para evitar errores como:

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

en tu aplicación.


Pregunta anterior, pero Guzzle agrega la respuesta dentro del objeto de excepción. Así que un simple try-catch en GuzzleHttp/Exception/ClientException y luego usar getResponse en esa excepción para ver qué error de 400 niveles y continuar desde allí.


Si la Excepción se lanza en ese bloque de try , en el peor de los casos, la Exception debe detectar cualquier cosa no detectada.

Considere que la primera parte de la prueba es arrojar la excepción y envolverla en el bloque try también.


GuzzleHttp/Exception/BadResponseException como lo sugiere @dado. Pero un día recibí GuzzleHttp/Exception/ConnectException cuando DNS para el dominio no estaba disponible. Así que mi sugerencia es - atrapar GuzzleHttp/Exception/ConnectException para estar seguro acerca de los errores de DNS también.


try { } catch (GuzzleHttp/Subscriber/HttpError $e) { //catches all 4xx and 5xx status codes }