Handle Guzzle exception and get HTTP body

I would like to handle errors from Guzzle when the server returns 4xx and 5xx status codes. I make a request like this:

$client = $this->getGuzzleClient();
$request = $client->post($url, $headers, $value);
try {
    $response = $request->send();
    return $response->getBody();
} catch (\Exception $e) {
    // How can I get the response body?
}

$e->getMessage returns code info but not the body of the HTTP response. How can I get the response body?


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

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.


While the answers above are good they will not catch network errors. As Mark mentioned, BadResponseException is just a super class for ClientException and ServerException. But RequestException is also a super class of BadResponseException. RequestException will be thrown for not only 400 and 500 errors but network errors and infinite redirects too. So let's say you request the page below but your network is playing up and your catch is only 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);
  }

}