Próbuję wyłapać wyjątki z zestawu testów, które uruchamiam w API, które tworzę i używam Guzzle do korzystania z metod API. Mam testy opakowane w blok try / catch, ale nadal generują nieobsłużone błędy wyjątków. Dodanie detektora zdarzeń zgodnie z opisem w ich dokumentach wydaje się nic nie robić. Muszę być w stanie pobrać odpowiedzi, które mają kody HTTP 500, 401, 400, w rzeczywistości wszystko, co nie jest 200, ponieważ system ustawi najbardziej odpowiedni kod na podstawie wyniku połączenia, jeśli to nie zadziała .
Aktualny przykład kodu
foreach($tests as $test){
$client = new Client($api_url);
$client->getEventDispatcher()->addListener('request.error', function(Event $event) {
if ($event['response']->getStatusCode() == 401) {
$newResponse = new Response($event['response']->getStatusCode());
$event['response'] = $newResponse;
$event->stopPropagation();
}
});
try {
$client->setDefaultOption('query', $query_string);
$request = $client->get($api_version . $test['method'], array(), isset($test['query'])?$test['query']:array());
// Do something with Guzzle.
$response = $request->send();
displayTest($request, $response);
}
catch (Guzzle\Http\Exception\ClientErrorResponseException $e) {
$req = $e->getRequest();
$resp =$e->getResponse();
displayTest($req,$resp);
}
catch (Guzzle\Http\Exception\ServerErrorResponseException $e) {
$req = $e->getRequest();
$resp =$e->getResponse();
displayTest($req,$resp);
}
catch (Guzzle\Http\Exception\BadResponseException $e) {
$req = $e->getRequest();
$resp =$e->getResponse();
displayTest($req,$resp);
}
catch( Exception $e){
echo "AGH!";
}
unset($client);
$client=null;
}
Nawet z konkretnym blokiem catch dla typu rzuconego wyjątku wciąż wracam
Fatal error: Uncaught exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message 'Client error response [status code] 401 [reason phrase] Unauthorized [url]
i jak można się spodziewać, wszystkie operacje na stronie zostają zatrzymane. Dodanie złapania BadResponseException pozwoliło mi poprawnie wyłapać 404, ale wydaje się, że nie działa to dla odpowiedzi 500 lub 401. Czy ktoś może zasugerować, gdzie idę źle?
źródło
use
wyjątki, być może będziesz musiał poprzedzić je znakiem ``, aby jawnie określić klasę FQ. Na przykład „\ Guzzle \ Http \ Exception \ ClientErrorResponseException”Odpowiedzi:
Jeśli wyjątek jest rzucany w tym
try
bloku, w najgorszym przypadkuException
powinien złapać coś, co nie zostało złapane.Weź pod uwagę, że pierwsza część testu polega na wyrzuceniu wyjątku i zawinięcie go również w
try
bloku.źródło
W zależności od projektu może być konieczne wyłączenie wyjątków dla guzzle. Czasami reguły kodowania nie zezwalają na wyjątki do sterowania przepływem. Możesz wyłączyć wyjątki dla Guzzle 3 w następujący sposób:
$client = new \Guzzle\Http\Client($httpBase, array( 'request.options' => array( 'exceptions' => false, ) ));
Nie wyłącza to wyjątków curl dla czegoś takiego jak limity czasu, ale teraz możesz łatwo uzyskać każdy kod stanu:
$request = $client->get($uri); $response = $request->send(); $statuscode = $response->getStatusCode();
Aby sprawdzić, czy masz prawidłowy kod, możesz użyć czegoś takiego:
if ($statuscode > 300) { // Do some error handling }
... lub lepiej obsłuż wszystkie oczekiwane kody:
if (200 === $statuscode) { // Do something } elseif (304 === $statuscode) { // Nothing to do } elseif (404 === $statuscode) { // Clean up DB or something like this } else { throw new MyException("Invalid response from api..."); }
Dla Guzzle 5.3
$client = new \GuzzleHttp\Client(['defaults' => [ 'exceptions' => false ]] );
Dzięki @mika
Dla Guzzle 6
$client = new \GuzzleHttp\Client(['http_errors' => false]);
źródło
break
;-) Ale na pewno byłoby dobrym rozwiązaniem, gdybyś miał wiele kodów statusu, które musisz obsługiwać w ten sam sposób. Wolęif
, bo przełącznik tylko obsługuje==
.request.options
. Rozwiązałem mój problem i zaoszczędziłem na poprawnym wyszukiwaniu. :)Aby złapać błędy Guzzle, możesz zrobić coś takiego:
try { $response = $client->get('/not_found.xml')->send(); } catch (Guzzle\Http\Exception\BadResponseException $e) { echo 'Uh oh! ' . $e->getMessage(); }
... ale aby móc "zarejestrować" lub "ponownie wysłać" swoje żądanie, spróbuj czegoś takiego:
// Add custom error handling to any request created by this client $client->getEventDispatcher()->addListener( 'request.error', function(Event $event) { //write log here ... if ($event['response']->getStatusCode() == 401) { // create new token and resend your request... $newRequest = $event['request']->clone(); $newRequest->setHeader('X-Auth-Header', MyApplication::getNewAuthToken()); $newResponse = $newRequest->send(); // Set the response object of the request without firing more events $event['response'] = $newResponse; // You can also change the response and fire the normal chain of // events by calling $event['request']->setResponse($newResponse); // Stop other events from firing when you override 401 responses $event->stopPropagation(); } });
... lub jeśli chcesz „zatrzymać propagację zdarzeń”, możesz przesłonić detektor zdarzeń (z wyższym priorytetem niż -255) i po prostu zatrzymać propagację zdarzeń.
$client->getEventDispatcher()->addListener('request.error', function(Event $event) { if ($event['response']->getStatusCode() != 200) { // Stop other events from firing when you get stytus-code != 200 $event->stopPropagation(); } });
to dobry pomysł, aby uniknąć błędów związanych z żartem, takich jak:
request.CRITICAL: Uncaught PHP Exception Guzzle\Http\Exception\ClientErrorResponseException: "Client error response
we wniosku.
źródło
W moim przypadku
Exception
wrzuciłem plik z przestrzenią nazw, więc php próbował złapać,My\Namespace\Exception
więc nie wychwytuje żadnych wyjątków.Warto sprawdzić, czy
catch (Exception $e)
szuka odpowiedniejException
klasy.Po prostu spróbuj
catch (\Exception $e)
(z tym\
tam) i zobacz, czy to działa.źródło
Musisz dodać dodatkowy parametr z http_errors => false
$request = $client->get($url, ['http_errors' => false]);
źródło
Stare pytanie, ale Guzzle dodaje odpowiedź w obiekcie wyjątku. A więc po prostu spróbuj złapać,
GuzzleHttp\Exception\ClientException
a następnie użyćgetResponse
tego wyjątku, aby zobaczyć, jaki błąd 400 poziomu i kontynuować od tego momentu.źródło
I był zaraźliwy
GuzzleHttp\Exception\BadResponseException
jak @dado sugeruje. Ale pewnego dnia dostałem,GuzzleHttp\Exception\ConnectException
kiedy DNS dla domeny nie był dostępny. Tak więc moja sugestia jest taka - złapGuzzleHttp\Exception\ConnectException
się również na błędach DNS.źródło
GuzzleHttp\Exception\RequestException
który jest rodzicemConnectException
,BadResponseException
aTooManyRedirectsException
.Chcę zaktualizować odpowiedź dotyczącą obsługi wyjątków w Psr-7 Guzzle, Guzzle7 i HTTPClient (ekspresyjne, minimalne API wokół klienta HTTP Guzzle dostarczonego przez laravel).
Guzzle7 (to samo działa również dla Guzzle 6)
Korzystając z RequestException , RequestException przechwytuje każdy wyjątek, który może zostać zgłoszony podczas przesyłania żądań.
try{ $client = new \GuzzleHttp\Client(['headers' => ['Authorization' => 'Bearer ' . $token]]); $guzzleResponse = $client->get('/foobar'); // or can use // $guzzleResponse = $client->request('GET', '/foobar') if ($guzzleResponse->getStatusCode() == 200) { $response = json_decode($guzzleResponse->getBody(),true); //perform your action with $response } } catch(\GuzzleHttp\Exception\RequestException $e){ // you can catch here 400 response errors and 500 response errors // You can either use logs here use Illuminate\Support\Facades\Log; $error['error'] = $e->getMessage(); $error['request'] = $e->getRequest(); if($e->hasResponse()){ if ($e->getResponse()->getStatusCode() == '400'){ $error['response'] = $e->getResponse(); } } Log::error('Error occurred in get request.', ['error' => $error]); }catch(Exception $e){ //other errors }
Psr7 Guzzle
use GuzzleHttp\Psr7; use GuzzleHttp\Exception\RequestException; try { $client->request('GET', '/foo'); } catch (RequestException $e) { $error['error'] = $e->getMessage(); $error['request'] = Psr7\Message::toString($e->getRequest()); if ($e->hasResponse()) { $error['response'] = Psr7\Message::toString($e->getResponse()); } Log::error('Error occurred in get request.', ['error' => $error]); }
W przypadku HTTPClient
use Illuminate\Support\Facades\Http; try{ $response = Http::get('http://api.foo.com'); if($response->successful()){ $reply = $response->json(); } if($response->failed()){ if($response->clientError()){ //catch all 400 exceptions Log::debug('client Error occurred in get request.'); $response->throw(); } if($response->serverError()){ //catch all 500 exceptions Log::debug('server Error occurred in get request.'); $response->throw(); } } }catch(Exception $e){ //catch the exception here }
źródło