Исключение исключений из Guzzle - программирование
Подтвердить что ты не робот

Исключение исключений из Guzzle

Я пытаюсь поймать исключения из набора тестов, которые я запускаю на 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 позволило мне правильно поймать 404s, но это, похоже, не работает для 500 или 401 ответов. Может ли кто-нибудь предложить, где я ошибаюсь, пожалуйста.

4b9b3361

Ответ 1

Если исключение выбрано в этом блоке try, то в худшем случае Exception должен ловить что-либо неотображенное.

Учтите, что первая часть теста бросает исключение и завершает его в блок try.

Ответ 2

В зависимости от вашего проекта может потребоваться отключение исключений для жужжания. Иногда правила кодирования запрещают исключения для управления потоком. Вы можете отключить исключения для 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...");
}

Для Guzzle 5.3

$client = new \GuzzleHttp\Client(['defaults' => [ 'exceptions' => false ]] );

Благодаря @mika

Для Guzzle 6

$client = new \GuzzleHttp\Client(['http_errors' => false]);

Ответ 3

Чтобы поймать ошибки Guzzle, вы можете сделать что-то вроде этого:

try {
    $response = $client->get('/not_found.xml')->send();
} catch (Guzzle\Http\Exception\BadResponseException $e) {
    echo 'Uh oh! ' . $e->getMessage();
}

... но, чтобы иметь возможность "регистрировать" или "повторно отправлять" ваш запрос, попробуйте что-то вроде этого:

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

});

... или если вы хотите "остановить распространение событий", вы можете отключить прослушиватель событий (с более высоким приоритетом, чем -255), и просто прекратить распространение события.

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

Это хорошая идея предотвратить ошибки жужжания, например:

request.CRITICAL: Uncaught PHP Exception Guzzle\Http\Exception\ClientErrorResponseException: "Client error response

в вашем приложении.

Ответ 4

Вам нужно добавить дополнительный параметр с помощью http_errors = > false

$request = $client->get($url, ['http_errors' => false]);

Ответ 5

Старый вопрос, но Guzzle добавляет ответ в объект исключения. Итак, простейший try-catch на GuzzleHttp\Exception\ClientException, а затем используя getResponse в этом исключении, чтобы увидеть, что такое ошибка на уровне 400 и дальше оттуда.

Ответ 6

В моем случае я бросал Exception в файл с именами, поэтому php попытался поймать My\Namespace\Exception, поэтому не обнаружил никаких исключений вообще.

Стоит проверить, находится ли catch (Exception $e) правильный класс Exception.

Просто попробуйте catch (\Exception $e) (с этим \ там) и посмотрите, работает ли он.

Ответ 7

Я ловил GuzzleHttp\Exception\BadResponseException, как предлагает @dado. Но однажды я получил GuzzleHttp\Exception\ConnectException, когда DNS для домена не был доступен. Поэтому мое предложение - catch GuzzleHttp\Exception\ConnectException, чтобы быть в безопасности и от ошибок DNS.

Ответ 8

    try {

    } catch (GuzzleHttp\Subscriber\HttpError $e) {
        //catches all 4xx and 5xx status codes
    }