Handle Guzzle exception and get HTTP body

扶醉桌前 提交于 2019-11-28 15:26:56
sebbo

Guzzle 3.x

Per the docs, you can catch the appropriate exception type (ClientErrorResponseException for 4xx errors) and call its getResponse() method to get the response object, then call getBody() on that:

use Guzzle\Http\Exception\ClientErrorResponseException;

...

try {
    $response = $request->send();
} catch (ClientErrorResponseException $exception) {
    $responseBody = $exception->getResponse()->getBody(true);
}

Passing true to the getBody function indicates that you want to get the response body as a string. Otherwise you will get it as instance of class Guzzle\Http\EntityBody.

Guzzle 6.x

Per the docs, the exception types you may need to catch are:

  • GuzzleHttp\Exception\ClientException for 400-level errors
  • GuzzleHttp\Exception\ServerException for 500-level errors
  • GuzzleHttp\Exception\BadResponseException for both (it's their superclass)

Code to handle such errors thus now looks something like this:

$client = new GuzzleHttp\Client;
try {
    $client->get('http://google.com/nosuchpage');    
}
catch (GuzzleHttp\Exception\ClientException $e) {
    $response = $e->getResponse();
    $responseBodyAsString = $response->getBody()->getContents();
}

While the answers above are good they will not deal with network errors, As Mark mentioned BadResponseException is just a super class for ClientException and ServerException. But RequestException is also a super class of BadRequestException. This will catch not only 400 and 500 errors but network errors too. So let's say you request the page below but your network is playing up and your catch is expecting a BadResponseException. Well your application will throw an error.

It's better in this case to expect RequestException and check for a response.

try {
  $client->get('http://123123123.com')
} catch (RequestException $e) {

  // If there are network errors, we need to ensure the application doesn't crash.
  // if $e->hasResponse is not null we can attempt to get the message
  // Otherwise, we'll just pass a network unavailable message.
  if ($e->hasResponse()) {
    $exception = (string) $e->getResponse()->getBody();
    $exception = json_decode($exception);
    return new JsonResponse($exception, $e->getCode());
  } else {
    return new JsonResponse($e->getMessage(), 503);
  }

}

As of 2019 here is what I elaborated from the answers above and Guzzle docs to handle the exception, get the response body, status code, message and the other sometimes valuable response items.

try {
    /**
     * We use Guzzle to make an HTTP request somewhere in the
     * following theMethodMayThrowException().
     */
    $result = theMethodMayThorwException();
} catch (\Exception $e) {
    /**
     * Here we actually catch the instance of GuzzleHttp\Psr7\Response
     * (find it in ./vendor/guzzlehttp/psr7/src/Response.php) with all
     * its own and its 'Message' trait's methods. See more explanations below.
     *
     * So you can have: HTTP status code, message, headers and body.
     */
    $response = $e->getResponse();
    var_dump($response->getStatusCode()); // HTTP status code
    var_dump($response->getReasonPhrase()); // Message
    var_dump((string) $response->getBody()); // Body
    var_dump($response->getHeaders()); // Headers array
    var_dump($response->hasHeader('Content-Type')); // Is the header presented
    var_dump($response->getHeader('Content-Type')[0]); // Concrete header value
}
// process $result etc. ...

Voila. You get the response's information in conveniently separated items.

Side Notes:

With catch clause we catch the inheritance chain PHP root exception class \Exception as Guzzle custom exceptions extend it.

This approach may be useful for use cases where Guzzle is used under the hood like in Laravel or AWS API PHP SDK so you cannot catch the genuine Guzzle exception.

In this case, the exception class may not be the one mentioned in the Guzzle docs (e.g. GuzzleHttp\Exception\RequestException as the root exception for Guzzle).

So you have to catch \Exception instead but bear in mind it is still the Guzzle exception class instance.

Though use with care. Those wrappers may make Guzzle $e->getResponse() object's genuine methods not available. In this case, you will have to look at the wrapper's actual exception source code and find out how to get status, message, etc. instead of using Guzzle $response's methods.

If you call Guzzle directly yourself you can catch GuzzleHttp\Exception\RequestException or any other one mentioned in their exceptions docs with respect to your use case conditions.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!