Обрабатывать исключение Guzzle и получать HTTP-теги

Я хотел бы обрабатывать ошибки от Guzzle, когда сервер возвращает коды состояния 4xx и 5xx. Я делаю запрос следующим образом:

$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 возвращает информацию о кодах, но не тело ответа HTTP. Как я могу получить тело ответа?

Ответ 1

Guzzle 3.x

Per , вы можете поймать соответствующий тип исключения (ClientErrorResponseException для ошибок 4xx) и вызвать его метод getResponse() для получения объекта ответа, затем вызовите getBody() на этом:

use Guzzle\Http\Exception\ClientErrorResponseException;

...

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

Передача true в функцию getBody означает, что вы хотите получить тело ответа как строку. В противном случае вы получите его как экземпляр класса Guzzle\Http\EntityBody.

Ответ 2

Guzzle 6.x

Per docs, типы исключений, которые могут вам понадобиться, следующие:

  • GuzzleHttp\Exception\ClientException для 400-уровневых ошибок
  • GuzzleHttp\Exception\ServerException для 500-уровневых ошибок
  • GuzzleHttp\Exception\BadResponseException для обоих (это их суперкласс)

Код для обработки таких ошибок теперь выглядит примерно так:

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

Ответ 3

В то время как ответы выше хорошо, они не будут иметь дело с сетевыми ошибками, поскольку Mark упоминает BadResponseException - это просто суперкласс для ClientException и ServerException. Но RequestException также является суперклассом BadRequestException. Это приведет не только к 400 и 500 ошибкам, но и к сетевым ошибкам. Итак, скажем, вы запрашиваете страницу ниже, но ваша сеть играет вверх, и ваш улов ожидает исключения BadResponseException. Ну, ваше приложение будет выдавать ошибку.

Лучше в этом случае ожидать RequestException и проверить ответ.

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

}

Ответ 4

Начиная с 2019 года, вот что я разработал из приведенных выше ответов и документов Guzzle для обработки исключения, получения тела ответа, кода состояния, сообщения и других, иногда полезных, элементов ответа.

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 methods. See more explanations below.
     *
     * So you can have: HTTP status code, message, headers and body.
     * Just check the exception object has the response before.
     */
    if ($e->hasResponse()) {
        $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. Вы получаете ответную информацию в удобно разделенных пунктах.

Примечания стороны:

С помощью предложения catch мы перехватываем класс исключений корневого исключения PHP-цепочки \Exception, как расширяют его пользовательские исключения в Guzzle.

Этот подход может быть полезен в тех случаях, когда Guzzle используется под капотом, как в Laravel или AWS API PHP SDK, поэтому вы не можете поймать подлинное исключение Guzzle.

В этом случае класс исключений может не совпадать с классом, упомянутым в документации по Guzzle (например, GuzzleHttp\Exception\RequestException как корневое исключение для Guzzle).

Поэтому вы должны поймать \Exception, но помните, что это все еще экземпляр класса исключений Guzzle.

Хотя используйте с осторожностью. Эти оболочки могут сделать подлинные методы объекта Guzzle $e->getResponse() недоступными. В этом случае вам придется взглянуть на фактический исходный код оболочки и выяснить, как получить статус, сообщение и т.д. Вместо использования методов Guzzle $response.

Если вы сами позвоните в Guzzle, вы можете поймать GuzzleHttp\Exception\RequestException или любого другого, упомянутого в их документах об исключениях, в отношении условий использования.