Chciałbym poradzić sobie z błędami Guzzle, gdy serwer zwraca kody stanu 4xx i 5xx. Składam taką prośbę:
$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
zwraca informacje o kodzie, ale nie treść odpowiedzi HTTP. Jak mogę uzyskać treść odpowiedzi?
Odpowiedzi:
Guzzle 3.x
Zgodnie z dokumentacją możesz złapać odpowiedni typ wyjątku (
ClientErrorResponseException
dla błędów 4xx) i wywołać jegogetResponse()
metodę, aby uzyskać obiekt odpowiedzi, a następnie wywołaćgetBody()
to:Przekazanie
true
dogetBody
funkcji wskazuje, że chcesz pobrać treść odpowiedzi jako ciąg. W przeciwnym razie otrzymasz go jako instancję klasyGuzzle\Http\EntityBody
.źródło
Guzzle 6.x
Zgodnie z dokumentacją typy wyjątków, które możesz potrzebować, to:
GuzzleHttp\Exception\ClientException
dla błędów 400-poziomowychGuzzleHttp\Exception\ServerException
dla błędów poziomu 500GuzzleHttp\Exception\BadResponseException
dla obojga (to ich superklasa)Kod do obsługi takich błędów wygląda teraz mniej więcej tak:
źródło
$response->getBody()->getContents()
zwróciłby pusty ciąg. Następnie natknąłem się na to w dokumentach :\GuzzleHttp\Psr7\str($e->getResponse())
Przesyłanie odpowiedzi jako ciągu Psr7 dało mi ładnie sformatowany i kompletny komunikat o błędzie.Psr7\str()
miałoby inne wyniki do->getContents()
. Czy masz minimalny przykład demonstrujący to, który może pozwolić mi to zrozumieć i być może zaktualizować tę odpowiedź?'http_errors' => false
opcję można przekazać w żądaniu Guzzle, co wyłącza rzucanie wyjątków. Następnie możesz pobrać$response->getBody()
treść bez względu na kod stanu, aw razie potrzeby możesz przetestować kod stanu za pomocą$response->getStatusCode()
.$response->getBody()->getContents()
daje mi pusty ciąg w jednym przypadku, nie rozumiem dlaczego. Ale użycie\GuzzleHttp\Psr7\str()
zwraca całą odpowiedź HTTP jako ciąg, a ja tylko treść HTTP. Jak wspomniano w dokumentacji , ciało może być używane przez odlewanie go na strunę.$stringBody = (string) $clientException->getResponse()->getBody();
\GuzzleHttp\Exception\RequestException
zamiast tego otrzymywałem, który zwrócił400
kod stanu. try {$ request-> api ('POST', 'endpoint.json'); } catch (RequestException $ e) {print_r ($ e-> getResponse () -> getBody () -> getContents ()); }Chociaż powyższe odpowiedzi są dobre, nie wyłapią błędów sieciowych. Jak wspomniał Mark, BadResponseException to po prostu super klasa dla ClientException i ServerException. Ale RequestException to także super klasa BadResponseException. RequestException zostanie zgłoszony nie tylko dla błędów 400 i 500, ale także dla błędów sieciowych i nieskończonych przekierowań. Powiedzmy więc, że żądasz poniższej strony, ale Twoja sieć działa, a Twój haczyk oczekuje tylko wyjątku BadResponseException. Twoja aplikacja zgłosi błąd.
W takim przypadku lepiej jest spodziewać się wyjątku RequestException i sprawdzić odpowiedź.
źródło
JsonResponse
klasa z Guzzle?JsonResponse
pochodzi z SymfonyOd 2019 r. Opracowałem na podstawie powyższych odpowiedzi i dokumentów Guzzle, aby obsłużyć wyjątek, uzyskać treść odpowiedzi, kod stanu, wiadomość i inne czasami cenne elementy odpowiedzi.
Voila. Otrzymujesz informacje o odpowiedzi w wygodnie oddzielonych pozycjach.
Uwagi dodatkowe:
Za pomocą
catch
klauzuli\Exception
łapiemy klasę wyjątku głównego PHP łańcucha dziedziczenia, ponieważ niestandardowe wyjątki Guzzle ją rozszerzają.To podejście może być przydatne w przypadkach użycia, w których Guzzle jest używane pod maską, jak w Laravel lub AWS API PHP SDK, więc nie możesz złapać prawdziwego wyjątku Guzzle.
W tym przypadku klasa wyjątku może nie być tą, o której mowa w dokumentacji Guzzle (np.
GuzzleHttp\Exception\RequestException
Jako główny wyjątek dla Guzzle).Więc
\Exception
zamiast tego musisz złapać, ale pamiętaj, że nadal jest to instancja klasy wyjątku Guzzle.Chociaż używaj ostrożnie. Te opakowania mogą sprawić,
$e->getResponse()
że oryginalne metody obiektu Guzzle będą niedostępne. W takim przypadku będziesz musiał spojrzeć na rzeczywisty kod źródłowy wyjątku opakowania i dowiedzieć się, jak uzyskać status, komunikat itp. Zamiast używać$response
metod Guzzle .Jeśli zadzwonisz bezpośrednio do Guzzle, możesz złapać
GuzzleHttp\Exception\RequestException
lub inny wymieniony w ich dokumentach wyjątków w odniesieniu do warunków twojego przypadku użycia.źródło
$response
obiekcie podczas obsługi wyjątków, chyba że zaznaczyłeś$e->hasResponse()
, w przeciwnym razie$response
może tak być,null
a każde wywołanie metod spowoduje błąd krytyczny.$e->hasResponse
wynik, metodę, która oczywiście nie istnieje dla wyjątków innych niż Guzzle. Więc jeśli zgłosisz wyjątek inny niż Guzzle ztheMethodMayThrowException()
, ten kod złapie go, spróbuje wywołać nieistniejącą metodę i zawiesi się z powodu nieistniejącej metody, skutecznie ukrywając prawdziwą przyczynę błędu. Lepiej byłoby złapaćGuzzleHttp\Exception\RequestException
zamiast tegoException
unikać.jeśli trafi
'http_errors' => false
w chlać opcji żądanie, wtedy byłoby przestać rzucać wyjątek podczas get 4xx lub 5xx błędu w następujący sposób:$client->get(url, ['http_errors' => false])
. następnie analizujesz odpowiedź, bez względu na to, czy jest w porządku, czy błąd, będzie w odpowiedzi, aby uzyskać więcej informacjiźródło