it-swarm.dev

اصطياد استثناءات من Guzzle

أحاول الحصول على استثناءات من مجموعة من الاختبارات التي أجريها على واجهة برمجة التطبيقات التي أطورها وأنا أستخدم Guzzle لاستهلاك أساليب واجهة برمجة التطبيقات. لقد حصلت على الاختبارات ملفوفة في كتلة 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 ردًا. يمكن لأي شخص أن يقترح أين أنا الخطأ من فضلك.

60
Eric Harth

إذا تم طرح الاستثناء في كتلة try ، فينبغي في سيناريو الحالة Exception في أسوأ الأحوال أن يلقي أي شيء بدون علم.

ضع في اعتبارك أن الجزء الأول من الاختبار هو رمي الاستثناء والتفافه في كتلة try أيضًا.

13
user2584140

اعتمادًا على مشروعك ، قد يكون تعطيل استثناءات guzzle ضروريًا. في بعض الأحيان ، لا تسمح قواعد الترميز باستثناءات التحكم في التدفق. يمكنك تعطيل الاستثناءات بالنسبة لـ Guzzle 3 مثل هذا:

$client = new \Guzzle\Http\Client($httpBase, array(
  'request.options' => array(
     'exceptions' => false,
   )
));

هذا لا يؤدي إلى تعطيل استثناءات حليقة لشيء مثل المهلات ، ولكن الآن يمكنك الحصول على كل رمز الحالة بسهولة:

$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

لغزل 6

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

للقبض على أخطاء 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();
    }
});

هذا هو فكرة جيدة لمنع الأخطاء guzzle مثل:

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

في التطبيق الخاص بك.

44
Dado

في حالتي كنت ألقى Exception على ملف بمساحة اسمية ، لذا حاول php التقاط My\Namespace\Exception وبالتالي ، لم ألاحظ أي استثناءات على الإطلاق.

يجدر التحقق مما إذا كان catch (Exception $e) يجد الفئة المناسبة Exception.

مجرد محاولة catch (\Exception $e) (مع ذلك \ هناك) ومعرفة ما إذا كان يعمل.

27
dmmd

تحتاج إلى إضافة معلمة إضافية مع http_errors => false

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

سؤال قديم ، ولكن يضيف Guzzle الاستجابة داخل كائن الاستثناء. لذا ، حاول تجربة بسيطة على GuzzleHttp\Exception\ClientException ، ثم استخدم getResponse في هذا الاستثناء لمعرفة ما الخطأ 400 مستوى والمستمر من هناك.

5
Carson Reinke

كنت اصطياد GuzzleHttp\Exception\BadResponseException كما يقترحdado. لكن في يوم من الأيام تلقيت GuzzleHttp\Exception\ConnectException عندما لم يكن DNS للنطاق متاحًا. لذلك اقتراحي هو - امسك GuzzleHttp\Exception\ConnectException لتكون آمنًا بشأن أخطاء DNS أيضًا.

2
Ivan Yarych