簡體   English   中英

從 Guzzle 捕獲異常

[英]Catching exceptions from 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 捕獲的添加使我能夠正確捕獲 404,但這似乎不適用於 500 或 401 響應。 任何人都可以建議我哪里出錯了。

根據您的項目,可能需要禁用 guzzle 異常。 有時編碼規則不允許流控制的異常。 您可以像這樣禁用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...");
}

對於狂飲 5.3

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

感謝@mika

對於狂飲 6

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

要捕獲 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

在您的應用程序中。

就我而言,我在命名空間文件上拋出Exception ,因此 php 試圖捕獲My\\Namespace\\Exception因此根本沒有捕獲任何異常。

值得檢查catch (Exception $e)是否找到了正確的Exception類。

只需嘗試catch (\\Exception $e) (使用那個\\ ),看看它是否有效。

如果在那個try塊中拋出異常,那么在最壞的情況下, Exception應該捕獲任何未捕獲的東西。

考慮到測試的第一部分是拋出異常並將其包裝在try塊中。

您需要使用 http_errors => false 添加一個額外的參數

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

老問題,但 Guzzle 在異常對象中添加了響應。 因此,對GuzzleHttp\\Exception\\ClientException進行簡單的 try-catch,然后對該異常使用getResponse以查看什么 400 級錯誤並從那里繼續。

正如@dado 所建議的那樣,我正在捕獲GuzzleHttp\\Exception\\BadResponseException 但是有一天,當域的 DNS 不可用時,我收到了GuzzleHttp\\Exception\\ConnectException 所以我的建議是 - 捕獲GuzzleHttp\\Exception\\ConnectException以確保 DNS 錯誤的安全。

我想更新 Psr-7 Guzzle、Guzzle7 和 HTTPClient(圍繞 laravel 提供的 Guzzle HTTP 客戶端的表達性、最小 API)中異常處理的答案。

Guzzle7(同樣適用於 Guzzle 6)

使用 RequestException ,RequestException 捕獲傳輸請求時可能拋出的任何異常。

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 狂飲

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]);
}

對於 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
 }

如果您使用的是最新版本的 6^ 並且您有一個 JSON 參數,則可以將'http_errors' => false與 JSON 一起添加到數組中,如下所示在此處輸入圖片說明

我一直在尋找這樣做,即在那里使用我的 JSON,但找不到直接的答案。

    try {

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM