Я пытаюсь перехватить исключения из набора тестов, которые я запускаю в разрабатываемом мной API, и использую Guzzle для использования методов API. У меня есть тесты, заключенные в блок try / catch, но он по-прежнему выдает необработанные ошибки исключения. Добавление прослушивателя событий, как описано в их документации, похоже, ничего не дает. Мне нужно получить ответы с кодами HTTP 500, 401, 400, фактически все, что не 200, поскольку система установит наиболее подходящий код на основе результата вызова, если он не сработал. .
Текущий пример кода
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;
}
Даже с конкретным блоком catch для выбранного типа исключения я все равно возвращаюсь
Fatal error: Uncaught exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message 'Client error response [status code] 401 [reason phrase] Unauthorized [url]
и все выполнение на странице останавливается, как и следовало ожидать. Добавление ловушки BadResponseException позволило мне правильно поймать 404, но, похоже, это не работает для 500 или 401 ответа. Может ли кто-нибудь подсказать, где я ошибаюсь, пожалуйста.
use
исключения, вам может потребоваться префикс ``, чтобы явно указать класс FQ. Так, например, '\ Guzzle \ Http \ Exception \ ClientErrorResponseException'Ответы:
Если в этом
try
блоке выбрасывается исключение, то в худшем случаеException
следует перехватить что-нибудь неперехваченное.Учтите, что первая часть теста выбрасывает исключение и также переносит его в
try
блок.источник
В зависимости от вашего проекта может потребоваться отключение исключений для жрать. Иногда правила кодирования запрещают исключения для управления потоком. Вы можете отключить исключения для Guzzle 3 следующим образом:
$client = new \Guzzle\Http\Client($httpBase, array( 'request.options' => array( 'exceptions' => false, ) ));
Это не отключает исключения curl для чего-то вроде тайм-аутов, но теперь вы можете легко получить любой код состояния:
$request = $client->get($uri); $response = $request->send(); $statuscode = $response->getStatusCode();
Чтобы проверить, есть ли у вас действительный код, вы можете использовать что-то вроде этого:
if ($statuscode > 300) { // Do some error handling }
... или лучше обработать все ожидаемые коды:
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..."); }
For Guzzle 5.3
$client = new \GuzzleHttp\Client(['defaults' => [ 'exceptions' => false ]] );
Thanks to @mika
For Guzzle 6
$client = new \GuzzleHttp\Client(['http_errors' => false]);
источник
break
;-) But sure, it would be a good solution if you have multiple status codes you have to handle in the same way. I preferif
, cause switch just supports==
.request.options
. Resolved my problem and saved me looking it up properly. :)To catch Guzzle errors you can do something like this:
try { $response = $client->get('/not_found.xml')->send(); } catch (Guzzle\Http\Exception\BadResponseException $e) { echo 'Uh oh! ' . $e->getMessage(); }
... but, to be able to "log" or "resend" your request try something like this:
// 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(); } });
... or if you want to "stop event propagation" you can overridde event listener (with a higher priority than -255) and simply stop event propagation.
$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(); } });
thats a good idea to prevent guzzle errors like:
request.CRITICAL: Uncaught PHP Exception Guzzle\Http\Exception\ClientErrorResponseException: "Client error response
in your application.
источник
In my case I was throwing
Exception
on a namespaced file, so php tried to catchMy\Namespace\Exception
therefore not catching any exceptions at all.Worth checking if
catch (Exception $e)
is finding the rightException
class.Just try
catch (\Exception $e)
(with that\
there) and see if it works.источник
You need to add a extra parameter with http_errors => false
$request = $client->get($url, ['http_errors' => false]);
источник
Old question, but Guzzle adds the response within the exception object. So a simple try-catch on
GuzzleHttp\Exception\ClientException
and then usinggetResponse
on that exception to see what 400-level error and continuing from there.источник
I was catching
GuzzleHttp\Exception\BadResponseException
as @dado is suggesting. But one day I gotGuzzleHttp\Exception\ConnectException
when DNS for domain wasn't available. So my suggestion is - catchGuzzleHttp\Exception\ConnectException
to be safe about DNS errors as well.источник
GuzzleHttp\Exception\RequestException
which is the parent ofConnectException
,BadResponseException
andTooManyRedirectsException
.I want to update the answer for exception handling in Psr-7 Guzzle, Guzzle7 and HTTPClient(expressive, minimal API around the Guzzle HTTP client provided by laravel).
Guzzle7 (same works for Guzzle 6 as well)
Using RequestException, RequestException catches any exception that can be thrown while transferring requests.
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]); }
For 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 }
источник