php 从 Guzzle 捕获异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17658283/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 16:13:48  来源:igfitidea点击:

Catching exceptions from Guzzle

phpapifunctional-testingguzzle

提问by Eric

I'm trying to catch exceptions from a set of tests I'm running on an API I'm developing and I'm using Guzzle to consume the API methods. I've got the tests wrapped in a try/catch block but it is still throwing unhandled exception errors. Adding an event listener as described in their docs doesn't seem to do anything. I need to be able to retrieve the responses that have HTTP codes of 500, 401, 400, in fact anything that isn't 200 as the system will set the most appropriate code based on the result of the call if it didn't work.

我正在尝试从我正在开发的 API 上运行的一组测试中捕获异常,并且我正在使用 Guzzle 来使用 API 方法。我已经将测试包装在 try/catch 块中,但它仍然抛出未处理的异常错误。按照他们的文档中的描述添加事件侦听器似乎没有任何作用。我需要能够检索 HTTP 代码为 500、401、400 的响应,实际上任何不是 200 的响应,因为如果它不起作用,系统将根据调用结果设置最合适的代码.

Current code example

当前代码示例

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;

    }

Even with the specific catch block for the thrown exception type I am still getting back

即使对于抛出的异常类型有特定的 catch 块,我仍然会回来

Fatal error: Uncaught exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message 'Client error response [status code] 401 [reason phrase] Unauthorized [url]

and all execution on the page stops, as you'd expect. The addition of the BadResponseException catch allowed me to catch 404s correctly, but this doesn't seem to work for 500 or 401 responses. Can anyone suggest where I am going wrong please.

正如您所期望的那样,页面上的所有执行都会停止。BadResponseException 捕获的添加使我能够正确捕获 404,但这似乎不适用于 500 或 401 响应。任何人都可以建议我哪里出错了。

采纳答案by dmmd

If the Exception is being thrown in that tryblock then at worst case scenario Exceptionshould be catching anything uncaught.

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

Consider that the first part of the test is throwing the Exception and wrap that in the tryblock as well.

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

回答by Trendfischer

Depending on your project, disabling exceptions for guzzle might be necessary. Sometimes coding rules disallow exceptions for flow control. You can disable exceptions for Guzzle 3like this:

根据您的项目,可能需要禁用 guzzle 异常。有时编码规则不允许流控制的异常。您可以像这样禁用Guzzle 3 的异常:

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

This does not disable curl exceptions for something like timeouts, but now you can get every status code easily:

这不会禁用诸如超时之类的 curl 异常,但现在您可以轻松获取每个状态代码:

$request = $client->get($uri);
$response = $request->send();
$statuscode = $response->getStatusCode();

To check, if you got a valid code, you can use something like this:

要检查,如果你有一个有效的代码,你可以使用这样的东西:

if ($statuscode > 300) {
  // Do some error handling
}

... or better handle all expected codes:

...或更好地处理所有预期的代码:

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

对于狂饮 5.3

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

Thanks to @mika

感谢@mika

For Guzzle 6

对于狂饮 6

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

回答by Dado

To catch Guzzle errors you can do something like this:

要捕获 Guzzle 错误,您可以执行以下操作:

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

... but, to be able to "log" or "resend" your request try something like this:

...但是,为了能够“记录”或“重新发送”您的请求,请尝试以下操作:

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

});

... or if you want to "stop event propagation" you can overridde event listener (with a higher priority than -255) and simply stop event propagation.

...或者如果您想“停止事件传播”,您可以覆盖事件侦听器(优先级高于 -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();
    }
});

thats a good idea to prevent guzzle errors like:

这是一个好主意,以防止大量错误,例如:

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

in your application.

在您的应用程序中。

回答by dmmd

In my case I was throwing Exceptionon a namespaced file, so php tried to catch My\Namespace\Exceptiontherefore not catching any exceptions at all.

在我的情况下,我抛出Exception了一个命名空间文件,所以 php 试图捕获My\Namespace\Exception因此根本没有捕获任何异常。

Worth checking if catch (Exception $e)is finding the right Exceptionclass.

值得检查是否catch (Exception $e)找到了合适的Exception课程。

Just try catch (\Exception $e)(with that \there) and see if it works.

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

回答by andr3s2

You need to add a extra parameter with http_errors => false

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

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

回答by Carson Reinke

Old question, but Guzzle adds the response within the exception object. So a simple try-catch on GuzzleHttp\Exception\ClientExceptionand then using getResponseon that exception to see what 400-level error and continuing from there.

老问题,但 Guzzle 在异常对象中添加了响应。所以一个简单的 try-catch onGuzzleHttp\Exception\ClientException然后使用getResponse该异常来查看什么 400 级错误并从那里继续。

回答by Ivan Yarych

I was catching GuzzleHttp\Exception\BadResponseExceptionas @dado is suggesting. But one day I got GuzzleHttp\Exception\ConnectExceptionwhen DNS for domain wasn't available. So my suggestion is - catch GuzzleHttp\Exception\ConnectExceptionto be safe about DNS errors as well.

GuzzleHttp\Exception\BadResponseException正如@dado 所建议的那样,我正在赶上。但有一天,GuzzleHttp\Exception\ConnectException当域的 DNS 不可用时,我得到了。所以我的建议是 - 抓住GuzzleHttp\Exception\ConnectExceptionDNS 错误也是安全的。