Guzzle 예외 처리 및 HTTP 본문 가져 오기


122

서버가 4xx 및 5xx 상태 코드를 반환 할 때 Guzzle의 오류를 처리하고 싶습니다. 다음과 같이 요청합니다.

$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
이 질문은이 질문과 관련이 있습니다. stackoverflow.com/questions/17658283/… 그리고 답변도 도움이 될 수 있습니다.
Trendfischer

답변:


84

Guzzle 3.x

워드 프로세서 , 당신은 (적절한 예외 유형 잡을 수 ClientErrorResponseException4XX 오류)를하고 전화 getResponse()응답 개체를 얻을 수있는 방법을 다음 호출 getBody()것을에 :

use Guzzle\Http\Exception\ClientErrorResponseException;

...

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

함수에 전달 하면 응답 본문을 문자열로 가져 오려고 함 truegetBody나타냅니다. 그렇지 않으면 클래스의 인스턴스로 얻을 수 있습니다 Guzzle\Http\EntityBody.


232

Guzzle 6.x

워드 프로세서 , 당신은 캐치해야 할 수도 예외 유형은 다음과 같습니다

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

12
나를 $response->getBody()->getContents()위해 빈 문자열을 반환합니다. 그때 나는이 운 좋게 발견 한 워드 프로세서 : \GuzzleHttp\Psr7\str($e->getResponse()) 응답 캐스팅 Psr7 문자열이 나에게 친절하게 포맷하고 완전한 오류 메시지를 가지고있다.
Andy Place

3
@AndyPlace PSR 7 (이 답변을 작성했을 때 링크하는 문서 섹션에서 참조하지 않았지만 지금은 참조)을 살펴본 후 왜 전화 Psr7\str()가 다른 결과를 가져 오는지 분명하지 않습니다. 에 ->getContents(). 이것을 보여주는 최소한의 예가 있습니까?이를 이해하고 아마도이 답변을 업데이트 할 수 있습니까?
Mark Amery

24
'http_errors' => false예외 발생을 비활성화하는 Guzzle 요청에서 옵션을 전달할 수 있다는 점을 언급 할 가치 가 있습니다. 그런 다음 $response->getBody()상태 코드에 관계없이 본문을 가져올 수 있으며 필요한 경우를 사용하여 상태 코드를 테스트 할 수 있습니다 $response->getStatusCode().
tremby

2
@AndyPlace $response->getBody()->getContents()로 한 경우에 빈 문자열을 제공하지만 이유를 이해할 수 없습니다. 그러나을 사용하면 \GuzzleHttp\Psr7\str()모든 HTTP 응답이 문자열로 반환되며 HTTP 본문 만 반환됩니다. 문서 에서 말했듯 이 본문은 문자열로 캐스팅하여 사용할 수 있습니다. $stringBody = (string) $clientException->getResponse()->getBody();
AnthonyB

1
나는 \GuzzleHttp\Exception\RequestException대신 400상태 코드 를 반환하는 것을 얻었지만 이것은 나를 위해 해냈습니다 . 시도 {$ request-> api ( 'POST', 'endpoint.json'); } catch (RequestException $ e) {print_r ($ e-> getResponse ()-> getBody ()-> getContents ()); }
jpcaparas 19-04-10

54

위의 답변은 좋지만 네트워크 오류를 포착하지 않습니다. Mark가 언급했듯이 BadResponseException은 ClientException 및 ServerException의 수퍼 클래스입니다. 그러나 RequestException은 BadResponseException의 수퍼 클래스이기도합니다. RequestException은 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);
  }

}

이다 JsonResponse목구멍에서 클래스는?
aexl

JsonResponseSymfony에서 제공
chap

14

2019 년 기준으로 예외를 처리하고 응답 본문, 상태 코드, 메시지 및 기타 유용한 응답 항목을 가져 오기 위해 위의 답변과 Guzzle 문서 에서 정교하게 설명한 내용이 있습니다.

try {
    /**
     * We use Guzzle to make an HTTP request somewhere in the
     * following theMethodMayThrowException().
     */
    $result = theMethodMayThrowException();
} catch (\GuzzleHttp\Exception\RequestException $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.
     * 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()); // Response message;
        var_dump((string) $response->getBody()); // Body, normally it is JSON;
        var_dump(json_decode((string) $response->getBody())); // Body as the decoded JSON;
        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. ...

짜잔. 편리하게 구분 된 항목으로 응답 정보를 얻을 수 있습니다.

사이드 노트 :

함께 catch절 우리는 상속 체인 PHP 루트 예외 클래스를 잡을 \Exception목구멍 사용자 정의 예외를 확장한다.

이 접근 방식은 Guzzle이 Laravel 또는 AWS API PHP SDK와 같이 내부적으로 사용되는 사용 사례에 유용 할 수 있으므로 진정한 Guzzle 예외를 포착 할 수 없습니다.

이 경우 예외 클래스는 Guzzle 문서에 언급 된 클래스가 아닐 수 있습니다 (예 : Guzzle GuzzleHttp\Exception\RequestException의 루트 예외).

따라서 \Exception대신 잡아야 하지만 여전히 Guzzle 예외 클래스 인스턴스임을 명심해야합니다.

조심해서 사용하십시오. 이러한 래퍼로 인해 Guzzle $e->getResponse()개체의 정품 메서드를 사용할 수 없게 될 수 있습니다. 이 경우, Guzzle $response의 메소드 를 사용하는 대신 래퍼의 실제 예외 소스 코드를보고 상태, 메시지 등을 얻는 방법을 찾아야 합니다.

Guzzle을 직접 직접 호출하면 사용 사례 조건과 관련하여 예외 문서에GuzzleHttp\Exception\RequestException 언급 된 다른 것을 잡을 수 있습니다 .


1
당신은 당신의 메서드 호출해서는 안 $response당신이 선택하지 않은 예외를 처리 할 때 개체를 $e->hasResponse()달리 $response할 수 null및 메서드 호출 치명적인 오류가 발생합니다.
pwaring

@pwaring, 사실. Guzzle 예외 문서에서 말한 그대로입니다. 답변을 업데이트했습니다. 감사합니다.
Valentine Shi

1
... 그러나 이것은 수정 후에도 여전히 문제가 있습니다. Guzzle 예외가 아닌 모든 예외를 포착 한 다음 $e->hasResponse결과를 호출 합니다. 물론 Guzzle이 아닌 예외에는 존재하지 않는 메서드입니다. 따라서에서 Guzzle이 아닌 예외를 발생 시키면 theMethodMayThrowException()이 코드가이를 포착하고 존재하지 않는 메서드를 호출하려고 시도하고 존재하지 않는 메서드로 인해 충돌하여 오류의 실제 원인을 효과적으로 숨 깁니다. 이것을 피하는 GuzzleHttp\Exception\RequestException대신 잡는 것이 좋습니다 Exception.
Mark Amery

1
@MarkAmery, 귀하의 요점은 완벽하게 유효합니다. 감사합니다. 답변 본문을 업데이트했습니다.
Valentine Shi

1
@JaberAlNahian 기뻐요 :) 그것이 내 의도였습니다. 언제나 환영합니다.
Valentine Shi

4

'http_errors' => falseguzzle 요청 옵션을 넣으면 다음과 같이 4xx 또는 5xx 오류가 발생하는 동안 예외 발생을 중지합니다.$client->get(url, ['http_errors' => false]) 합니다. 그런 다음 응답을 구문 분석합니다. 정상이든 오류이든 상관없이 더 많은 정보를 얻을 수 있습니다.


이 질문은 오류 예외
중지를
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.