Symfony:不能总是捕获异常

时间:2015-08-19 07:56:50

标签: php symfony exception-handling

对于这个模糊的标题感到抱歉,我不知道如何标题我的问题。

我通过kernel.exception服务在kernel.event_listener上收听。我在我的API中使用它来捕获所有异常并在JSON中对它们进行序列化,以便为API客户提供干净的错误处理。 我必须根据异常类型(我的HTTP异常,Symfony HTTP异常等)调整序列化。

当访问security.yml中access_control限制的部分时未对用户进行身份验证时,Symfony会抛出非HTTP Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException。在我的序列化程序中,非HTTP异常转换为500错误。由于InsufficientAuthenticationException 401 Unauthorized 错误,我必须单独捕获此异常并将其转换为我的特定于应用程序的异常类型。

示例:

# Find appropriate serialization
if($ex instanceof HttpErr\HttpErrorInterface) {
    # AppBundle\Exceptions\Http\*
    # A displayable error thrown intentionally by our controllers
    $status  = $ex->getStatusCode();
    $message = $ex->getMessage();
    $other   = $ex->getAdditionalDatas();
} elseif($ex instanceof InsufficientAuthenticationException) {
    throw new HttpErr\EUnauthorized; # look a this line
}
# more elseifs...

有效。捕获Symfony身份验证异常,然后在EUnauthorized中进行转换,然后将EUnauthorized序列化为JSON。但是你可以看到我在没有消息或previous异常的情况下抛出异常。 因为我想这样做:

elseif($ex instanceof InsufficientAuthenticationException) {
    # the standard argument $previous is in 2nd position in my exceptions instead of being 3rd.
    # the previous argument is important for me since it will keep context in error propagation.
    throw new HttpErr\EUnauthorized($ex->getMessage(), $ex);
}

当我这样做时(因此,只添加两个参数),序列化停止工作,我的事件监听器未被调用且应用程序崩溃(在prod中,这将变成一个友好的WSoD):

enter image description here

为什么?

2 个答案:

答案 0 :(得分:0)

在第一个" if"您提取数据以进行序列化,在第二步中您只需重新抛出一个新的异常。

这个新的异常不再是kernel.exception流。它被正确抛出:你可以看到你已经显示了完整的异常堆栈。

理想情况下,您应该使用某种响应来结束onKernelException。

修改

我将通过参考Symfony文档和代码扩展我之前的答案。

HttpKernel docs

  

如果在HttpKernel :: handle中的任何一点抛出异常,则抛出另一个事件 - kernel.exception。在内部,handle函数的主体包含在try-catch块中。抛出任何异常时,将调度kernel.exception事件,以便系统可以某种方式响应异常。

因此,在handle函数中的异常之后调用您的侦听器,但正如您在source中看到的那样,handleException函数未提供try / catch。这基本上意味着不应该捕获在侦听器中抛出的异常。

在您的监听器中,您可以将当前异常与$event->setException(...)的新异常交换,或者尝试自己构建Response

无论如何,抛出一个新的Exception似乎不是正确的方法。遗憾的是,在没有涉及所有代码的情况下,我不知道为什么使用或不使用参数进行编码。

答案 1 :(得分:0)

我不知道这是否对您有帮助,但是我遇到了类似的问题我的事件监听器未调用且应用程序崩溃了。因此,我解决了该问题,并覆盖了 Kernel.php 文件中的一种方法,如下所示:

protected function initializeContainer() {

    try {
        $container = parent::initializeContainer();
    } catch (\Throwable $throwable){
        // MY CATCH CODE GOES HERE
    }
    return $container;
}

您还可以连接到其他内核方法并覆盖它们。
注意:我正在使用Symfony 4.2。*