Php 从狂饮中捕捉异常

Php 从狂饮中捕捉异常,php,api,functional-testing,guzzle,Php,Api,Functional Testing,Guzzle,我正试图从我正在开发的API上运行的一组测试中捕获异常,并使用Guzzle使用API方法。我已经将测试包装在一个try/catch块中,但它仍然抛出未处理的异常错误。按照文档中的描述添加事件侦听器似乎没有任何作用。我需要能够检索HTTP代码为500、401、400的响应,事实上不是200的任何响应,因为如果调用不起作用,系统将根据调用结果设置最合适的代码 当前代码示例 foreach($tests as $test){ $client = new Client($api_url

我正试图从我正在开发的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个响应。有人能告诉我哪里出错了吗。

如果在
try
块中抛出异常,那么在最坏的情况下
异常应该捕获任何未捕获的内容


考虑到测试的第一部分是抛出异常,并将其包装在
try
块中。

要捕获狂饮错误,可以执行以下操作:

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

});
$client = new \Guzzle\Http\Client($httpBase, array(
  'request.options' => array(
     'exceptions' => false,
   )
));
if ($statuscode > 300) {
  // Do some error handling
}
试试看{
$response=$client->get('/not_found.xml')->send();
}捕获(Guzzle\Http\Exception\BadResponseException$e){
回音“噢!”。$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();
        }

});
$client = new \Guzzle\Http\Client($httpBase, array(
  'request.options' => array(
     'exceptions' => false,
   )
));
if ($statuscode > 300) {
  // Do some error handling
}
。。。或者,如果您想“停止事件传播”,您可以覆盖事件侦听器(优先级高于-255)并简单地停止事件传播

$client->getEventDispatcher()->addListener('request.error',函数(Event$Event){
如果($event['response']->getStatusCode()!=200){
//当您获得stytus代码!=200时,停止触发其他事件
$event->stopPropagation();
}
});
这是一个很好的方法来防止口吃错误,例如:

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

在应用程序中。

根据您的项目,可能需要禁用guzzle异常。有时,编码规则不允许流控制出现异常。您可以对Guzzle 3禁用异常,如下所示:

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

});
$client = new \Guzzle\Http\Client($httpBase, array(
  'request.options' => array(
     'exceptions' => false,
   )
));
if ($statuscode > 300) {
  // Do some error handling
}
这不会禁用超时之类的curl异常,但现在您可以轻松获取每个状态代码:

$request = $client->get($uri);
$response = $request->send();
$statuscode = $response->getStatusCode();
要进行检查,如果您获得了有效代码,可以使用以下内容:

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

});
$client = new \Guzzle\Http\Client($httpBase, array(
  'request.options' => array(
     'exceptions' => false,
   )
));
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]);

您需要添加一个带有http_errors=>false的额外参数

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

正如@dado所建议的那样,我正在捕获
GuzzleHttp\Exception\badsresponseexception
。但有一天,当域名的DNS不可用时,我得到了http\Exception\ConnectException。
因此,我的建议是-catch
Guzzle http\Exception\ConnectException
以确保DNS错误的安全。

老问题,但是Guzzle在异常对象中添加了响应。因此,简单地尝试捕获http\Exception\ClientException
,然后在该异常上使用
getResponse
,查看400级错误并从那里继续。

在我的例子中,我在一个命名空间文件上抛出
异常
,因此php试图捕获
My\Namespace\Exception
,因此根本没有捕获任何异常

值得检查的是
catch(Exception$e)
是否找到了正确的
Exception


只要尝试一下catch(\Exception$e)(在那里有
\
),看看它是否有效。

我想更新Psr-7 Guzzle、Guzzle7和HTTPClient(laravel提供的Guzzle HTTP客户端周围的表现性、最小API)中异常处理的答案

Guzzle 7(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狂饮 对于HTTPClient
如果您使用的是最新版本(比如6^),并且您有一个JSON参数,那么可以将
'http_errors'=>false
与JSON一起添加到数组中,如下所示


我一直在寻找答案,也就是说我的JSON在那里,但找不到一个直接的答案。

这段代码是在命名空间下吗?如果是这样的话,除非您
使用
ing异常,否则您可能需要在异常前面加上``以明确说明FQ类。例如,“\Guzzle\Http\Exception\ClientErrorResponseException”如果您是正确的,则在抛出异常的try/catch之外有一个测试。愚蠢的错误,谢谢你的帮助。曾经有过因缺少
中断而导致的奇怪错误吗但当然,如果你有多个状态码,你必须用同样的方式处理,这将是一个很好的解决方案。我更喜欢
如果
,因为开关只支持
=
。感谢您提到
请求。选项
。解决了我的问题,节省了我正确查找的时间。:)或者在Guzzle5.3中:$client=new\GuzzleHttp\client(['defaults'=>['exceptions'=>false]]);这使我在一个紧急项目上省了不少钱。谢谢Trendfischer等人!这在Guzzle 6中不再可能。你知道如何使用中间件来实现这一点吗?我希望我第一次遇到同样的问题时就滚动到这个错误。对我来说,我使用的是过时的Guzzle异常名称,而没有捕获通用异常,因为我不在根Namesapce。在异常开始捕获一般异常之前添加反斜杠,允许我在更具体的Guzzle异常上看到我的名称不匹配错误。请看评论。这也是我遇到的问题。好的回答文档:听起来你应该捕捉到
GuzzleHttp\Exception\RequestException
,它是
ConnectException
badsresponseexception
的父项