2013-07-15 108 views
43

我想從我正在開發的API上運行的一組測試中捕獲異常,並使用Guzzle來使用API​​方法。我已經將測試包裝在try/catch塊中,但它仍然拋出未處理的異常錯誤。按照他們的文檔中所述添加事件偵聽器似乎沒有任何作用。我需要能夠檢索HTTP代碼爲500,401,400的響應,實際上不是200的響應,因爲如果系統不工作,系統將根據通話結果設置最合適的代碼。從Guzzle捕捉異常

當前的代碼示例

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 catch的添加允許我正確捕獲404,但這似乎不適用於500或401響應。任何人都可以建議我哪裏錯了請。

+3

此代碼是否在命名空間下?如果是這樣,除非你使用例外,你可能需要用'\'來前綴它們來顯式聲明FQ類。因此,例如'\ Guzzle \ Http \ Exception \ ClientErrorResponseException' –

回答

9

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

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

+1

你是對的,在try/catch之外有一個拋出異常的測試。愚蠢的錯誤,感謝您的幫助。 –

39

要趕上狂飲錯誤,你可以做這樣的事情:

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 

+1

這在Guzzle 6中不再可能。任何想法如何使用中間件來做到這一點? – fnagel

72

根據您的項目,可能需要禁用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..."); 
} 

For Guzzle 5。3

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

由於@mika

對於狂飲6

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

曾經有一個奇怪的缺陷造成的'break';-)但是肯定的是,如果你有多個狀態碼你必須以相同的方式處理,這將是一個很好的解決方案。我更喜歡'if',因爲switch只支持'=='。 – Trendfischer

+0

感謝您提及'request.options'。解決了我的問題,並保存我正確地查找它。 :) – DanielM

+2

或在Guzzle5.3中:$ client = new \ GuzzleHttp \ Client(['defaults'=> [ 'exceptions'=> false ]] ); – mika

5

您需要添加一個額外的參數與http_errors =>假

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

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

@dado建議我正在捕捉GuzzleHttp\Exception\BadResponseException。但有一天,當域名的DNS不可用時,我得到了GuzzleHttp\Exception\ConnectException。 所以我的建議是 - 趕上GuzzleHttp\Exception\ConnectException以確保DNS錯誤的安全。

3

老問題,但Guzzle在異常對象內添加了響應。因此,在GuzzleHttp\Exception\ClientException上嘗試一下,然後在該異常上使用getResponse來查看400級別的錯誤,並從那裏繼續。

4

在我的情況下,我把Exception扔在命名空間的文件上,所以php試圖趕上My\Namespace\Exception因此沒有捕獲任何異常。

值得檢查catch (Exception $e)是否找到合適的Exception類。

只是嘗試catch (\Exception $e)(與那\),看看它是否工作。