Catching exceptions from Guzzle

前端 未结 8 1744
情歌与酒
情歌与酒 2020-11-30 22:07

I\'m trying to catch exceptions from a set of tests I\'m running on an API I\'m developing and I\'m using Guzzle to consume the API methods. I\'ve got the tests wrapped in a

相关标签:
8条回答
  • 2020-11-30 22:38

    I want to update the answer for exception handling in Psr-7 Guzzle, Guzzle7 and HTTPClient(expressive, minimal API around the Guzzle HTTP client provided by laravel).

    Guzzle7 (same works for Guzzle 6 as well)

    Using RequestException, RequestException catches any exception that can be thrown while transferring requests.

    try{
      $client = new \GuzzleHttp\Client(['headers' => ['Authorization' => 'Bearer ' . $token]]);
      
      $guzzleResponse = $client->get('/foobar');
      // or can use
      // $guzzleResponse = $client->request('GET', '/foobar')
        if ($guzzleResponse->getStatusCode() == 200) {
             $response = json_decode($guzzleResponse->getBody(),true);
             //perform your action with $response 
        } 
    }
    catch(\GuzzleHttp\Exception\RequestException $e){
       // you can catch here 400 response errors and 500 response errors
       // You can either use logs here use Illuminate\Support\Facades\Log;
       $error['error'] = $e->getMessage();
       $error['request'] = $e->getRequest();
       if($e->hasResponse()){
           if ($e->getResponse()->getStatusCode() == '400'){
               $error['response'] = $e->getResponse(); 
           }
       }
       Log::error('Error occurred in get request.', ['error' => $error]);
    }catch(Exception $e){
       //other errors 
    }
    

    Psr7 Guzzle

    use GuzzleHttp\Psr7;
    use GuzzleHttp\Exception\RequestException;
    
    try {
        $client->request('GET', '/foo');
    } catch (RequestException $e) {
        $error['error'] = $e->getMessage();
        $error['request'] = Psr7\Message::toString($e->getRequest());
        if ($e->hasResponse()) {
            $error['response'] = Psr7\Message::toString($e->getResponse());
        }
        Log::error('Error occurred in get request.', ['error' => $error]);
    }
    

    For HTTPClient

    use Illuminate\Support\Facades\Http;
    try{
        $response = Http::get('http://api.foo.com');
        if($response->successful()){
            $reply = $response->json();
        }
        if($response->failed()){
            if($response->clientError()){
                //catch all 400 exceptions
                Log::debug('client Error occurred in get request.');
                $response->throw();
            }
            if($response->serverError()){
                //catch all 500 exceptions
                Log::debug('server Error occurred in get request.');
                $response->throw();
            }
            
        }
     }catch(Exception $e){
         //catch the exception here
     }
    
    
    0 讨论(0)
  • 2020-11-30 22:41

    To catch Guzzle errors you can do something like this:

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

    ... but, to be able to "log" or "resend" your request try something like this:

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

    ... or if you want to "stop event propagation" you can overridde event listener (with a higher priority than -255) and simply stop event propagation.

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

    thats a good idea to prevent guzzle errors like:

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

    in your application.

    0 讨论(0)
  • 2020-11-30 22:43

    Depending on your project, disabling exceptions for guzzle might be necessary. Sometimes coding rules disallow exceptions for flow control. You can disable exceptions for Guzzle 3 like this:

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

    This does not disable curl exceptions for something like timeouts, but now you can get every status code easily:

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

    To check, if you got a valid code, you can use something like this:

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

    ... or better handle all expected codes:

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

    For Guzzle 5.3

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

    Thanks to @mika

    For Guzzle 6

    $client = new \GuzzleHttp\Client(['http_errors' => false]);
    
    0 讨论(0)
  • 2020-11-30 22:47

    In my case I was throwing Exception on a namespaced file, so php tried to catch My\Namespace\Exception therefore not catching any exceptions at all.

    Worth checking if catch (Exception $e) is finding the right Exception class.

    Just try catch (\Exception $e) (with that \ there) and see if it works.

    0 讨论(0)
  • 2020-11-30 22:48

    If the Exception is being thrown in that try block then at worst case scenario Exception should be catching anything uncaught.

    Consider that the first part of the test is throwing the Exception and wrap that in the try block as well.

    0 讨论(0)
  • 2020-11-30 22:53

    You need to add a extra parameter with http_errors => false

    $request = $client->get($url, ['http_errors' => false]);
    
    0 讨论(0)
提交回复
热议问题