Guzzle istisnasını işleyin ve HTTP gövdesini alın


122

Sunucu 4xx ve 5xx durum kodlarını döndürdüğünde Guzzle'dan kaynaklanan hataları ele almak istiyorum. Bunun gibi bir istekte bulunuyorum:

$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->getMessagekod bilgilerini döndürür, ancak HTTP yanıtının gövdesini döndürmez. Müdahale gövdesini nasıl alabilirim?


1
Bu soru, stackoverflow.com/questions/17658283/… sorusuyla ilgilidir ve buradaki yanıtlar da yardımcı olabilir.
Trendfischer

Yanıtlar:


84

Guzzle 3.x

Dokümanlar uyarınca , uygun istisna türünü ( ClientErrorResponseException4xx hataları için) getResponse()yakalayabilir ve yanıt nesnesini almak için yöntemini çağırabilir, ardından bunu çağırabilirsiniz getBody():

use Guzzle\Http\Exception\ClientErrorResponseException;

...

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

Geçme trueiçin getBodyişlevin bir dize olarak tepki gövdesini almak istediğinizi gösterir. Aksi takdirde, onu sınıf örneği olarak alırsınız Guzzle\Http\EntityBody.


232

Guzzle 6.x

Başına dokümanlar , sen catch gerekebilir istisna türleri şunlardır:

  • GuzzleHttp\Exception\ClientException 400 seviyeli hatalar için
  • GuzzleHttp\Exception\ServerException 500 seviyeli hatalar için
  • GuzzleHttp\Exception\BadResponseException ikisi için (bu onların süper sınıfı)

Bu tür hataları ele alacak kod, bu nedenle şimdi şuna benzer:

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

12
Benim $response->getBody()->getContents()için boş bir dize döndürürdü. Daha sonra belgelerde buna rastladım : \GuzzleHttp\Psr7\str($e->getResponse()) Yanıtı bir Psr7 String olarak yayınlamak bana güzel bir şekilde biçimlendirilmiş ve eksiksiz bir hata mesajı verdi.
Andy Place

3
@AndyPlace, PSR 7'ye bir göz attıktan sonra (bu yanıtı yazdığım sırada bağlantı verdiğim dokümanlar bölümünde referans gösterilmiyordu, ancak şimdi), aramanın neden Psr7\str()farklı sonuçlara sahip olacağı bana hemen açık değil için ->getContents(). Bunu gösteren, bunu anlamama ve belki de bu yanıtı güncellememe izin verecek minimal bir örneğiniz var mı?
Mark Amery

24
'http_errors' => falseİstisnaları atmayı devre dışı bırakan Guzzle isteğinde seçeneğin geçilebileceğini belirtmek gerekir . Daha sonra $response->getBody(), durum kodu ne olursa olsun bedeni alabilir ve gerekirse durum kodunu test edebilirsiniz $response->getStatusCode().
tremby

2
@AndyPlace $response->getBody()->getContents()bana bir durumda boş bir string verdiğinden nedenini anlamıyorum. Ancak kullanmak \GuzzleHttp\Psr7\str(), tüm HTTP yanıtını bir dize olarak döndürür ve yalnızca HTTP gövdesini kullanırdım. Söylediği gibi belgeler , vücut dizeye döküm tarafından kullanılabilir. $stringBody = (string) $clientException->getResponse()->getBody();
AnthonyB

1
Bu benim için yaptı, \GuzzleHttp\Exception\RequestExceptionbunun yerine bir 400durum kodu döndüren bir alıyordum . {$ istek-> api ('POST', 'endpoint.json') deneyin; } catch (RequestException $ e) {print_r ($ e-> getResponse () -> getBody () -> getContents ()); }
jpcaparas

55

Yukarıdaki cevaplar iyi olsa da ağ hatalarını yakalayamazlar. Mark'ın bahsettiği gibi BadResponseException, ClientException ve ServerException için sadece bir süper sınıftır. Ancak RequestException aynı zamanda BadResponseException'ın süper bir sınıfıdır. RequestException sadece 400 ve 500 hata için değil, aynı zamanda ağ hataları ve sonsuz yeniden yönlendirmeler için de atılır. Diyelim ki aşağıdaki sayfayı talep ettiniz, ancak ağınız çalışıyor ve yakalanmanız yalnızca bir BadResponseException bekliyor. Peki uygulamanız bir hata verecektir.

Bu durumda RequestException beklemek ve bir yanıt olup olmadığını kontrol etmek daha iyidir.

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

}

olan JsonResponseguzzle bir sınıf?
aexl

JsonResponseSymfony'den geliyor
bölüm

14

2019 itibariyle , istisnayı ele almak, yanıt gövdesini, durum kodunu, mesajı ve diğer bazen değerli yanıt öğelerini almak için yukarıdaki yanıtlardan ve Guzzle belgelerinden ayrıntılandırdığım şey burada .

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. ...

Voila. Yanıt bilgilerini uygun şekilde ayrılmış öğeler halinde alırsınız.

Yan Notlar:

catchMadde ile \Exception, Guzzle özel istisnaları onu genişlettikçe miras zinciri PHP kök istisna sınıfını yakalarız.

Bu yaklaşım, Laravel veya AWS API PHP SDK'da olduğu gibi Guzzle'ın başlık altında kullanıldığı kullanım durumları için yararlı olabilir, böylece gerçek Guzzle istisnasını yakalayamazsınız.

Bu durumda istisna sınıfı, Guzzle belgelerinde belirtilen sınıf olmayabilir (örn. GuzzleHttp\Exception\RequestException için kök istisnası olarak).

Yani \Exceptionbunun yerine yakalamalısınız, ancak bunun hala Guzzle istisna sınıfı örneği olduğunu unutmayın.

Dikkatli kullanılmasına rağmen. Bu sarmalayıcılar, Guzzle $e->getResponse()nesnesinin gerçek yöntemlerini kullanılamaz hale getirebilir . Bu durumda, Guzzle kullanmak yerine sarmalayıcının gerçek istisna kaynak koduna bakmanız ve durum, mesaj vb. Nasıl alınacağını öğrenmeniz gerekecektir.$response yöntemlerini .

Guzzle'ı doğrudan kendiniz ararsanız , kullanım durumunuzla ilgili olarak istisna belgelerindeGuzzleHttp\Exception\RequestException belirtilen herhangi birini yakalayabilirsiniz .


1
$responseKontrol etmedikçe istisnaları işlerken nesnenizde yöntemleri çağırmamalısınız $e->hasResponse(), aksi takdirde $responseolabilir nullve herhangi bir yöntem çağrısı ölümcül bir hataya neden olur.
2019

@pwaring, doğru. Aynen Guzzle istisnaları belgelerinin dediği gibi. Cevap güncellendi. Teşekkür ederim.
Valentine Shi

1
... ancak bu, düzeltmeden sonra hala sorunludur. Tüm istisnaları yakalıyorsunuz, sadece Guzzle olanları değil, ama sonra $e->hasResponsesonucu çağırıyorsunuz , tabii ki Guzzle dışı istisnalar için mevcut olmayan bir yöntem. Bu nedenle, Guzzle dışı bir istisnayı oluşturursanız theMethodMayThrowException(), bu kod onu yakalar, var olmayan bir yöntemi çağırmayı dener ve var olmayan yöntem nedeniyle çökerek hatanın gerçek nedenini etkili bir şekilde gizler. Bundan kaçınmak GuzzleHttp\Exception\RequestExceptionyerine yakalamak tercih Exceptionedilir.
Mark Amery

1
@MarkAmery, puanınız tamamen geçerli. Teşekkür ederim. Cevap gövdesini güncelledim.
Valentine Shi

1
@JaberAlNahian bunu duyduğuma sevindim :) niyetim buydu. Her zaman bekleriz.
Valentine Shi

4

koymak eğer 'http_errors' => falseguzzle istek seçeneklerinde, o zaman atış istisna dururdu olsun 4xx veya böyle 5xx hatası iken: $client->get(url, ['http_errors' => false]). daha sonra yanıtı ayrıştırırsınız, tamam veya hata olursa olsun, daha fazla bilgi için yanıtta olur


Bu soru, hata istisnalarının
durdurulmasını
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.