【问题标题】:Custom ExceptionListener picks up 403 & 404, but not 500 errors自定义 ExceptionListener 拾取 403 和 404,但不是 500 错误
【发布时间】:2014-03-06 12:40:23
【问题描述】:

与未回答的问题 Symfony 2.4: Why are 500 errors not caught by kernel.exception listener 完全相同。

我已经实现了一个自定义异常“处理程序”,它非常适用于 403 和 404 问题,但有 500 个错误(这是我真正想要处理的,因为我想在发生这种情况时从系统向自己发送电子邮件)不会触发我的自定义“处理程序”并继续表现得好像自定义“处理程序”不存在一样。代码比较简单:

从 app/config/config.yml 中提取:

services:
    core.exceptlistener:
        class: Pmb\LicensingBundle\Listener\ExceptionListener
        arguments:  ["@service_container", "@router"]
        tags:
            - { name: kernel.event_listener, event: kernel.exception, method: onKernelException, priority: 200 }

整个\Pmb\LicensingBundle\Listener\ExceptionListener.php:

<?php

namespace Pmb\LicensingBundle\Listener;

use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Bundle\TwigBundle\TwigEngine;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class ExceptionListener
{
    private $container;
    private $router;

    function __construct($container, $router) 
    {
        $this->container = $container;
        $this->router = $router;
    }

    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        $exception = $event->getException();
        die("test");
        $request = $this->container->get('request');
        $templating = $this->container->get('templating');    

        if ($exception instanceof \Symfony\Component\Security\Core\Exception\AccessDeniedException)
        {

            # If AJAX request, do show not error page.
            if ($request->isXmlHttpRequest()) 
            {
                $response = new Response(json_encode(array('error' => 'Access Denied: Not logged in as administrator')));
            }
            else
            {
                return new RedirectResponse($this->router->generate('login'));
            }

            $event->setResponse($response);
        }
        elseif ($exception->getStatusCode() == 404)
        {
            # If AJAX request, do show not error page.
            if ($request->isXmlHttpRequest()) 
            {
                $response = new Response(json_encode(array('error' => 'Requested route could not be found')));
            }
            else
            {
                $response = new Response($templating->render('PmbLicensingBundle:Exception:error404.html.twig', array(
                    'exception' => $exception
                )));
            }

            $event->setResponse($response);
        }       
        else
        {

            # TODO: Send Email
            # If AJAX request, do not show error page.
            if ($request->isXmlHttpRequest()) $response = new Response(json_encode(array('error' => 'Internal Server Error Encountered. Developer has been notified.')));
            else
            {
                $response = new Response($templating->render('PmbLicensingBundle:Exception:error500.html.twig', array(
                    'exception' => $exception
                )));
            }

        }
    }
}

我将die("test") 放在那里以验证根本没有调用“处理程序”,这不仅仅是我的 if-else 逻辑的问题。如前所述,这对任何 404 或 403 错误都非常有效,但 500 错误完全忽略了这一点并以默认方式运行。我很确定这与监听器服务的注册有关,但我找不到任何解释如何使其正常工作的东西。

编辑:以下是未按预期处理的错误的屏幕截图。我注意到一个(未定义的变量)die("test"); 实际上显示在底部,但在另一个(语法错误)上它没有显示,即使它们似乎都被 Symfony2 捕获了。进一步的测试表明 die("test"); 出现了,但是 die(">> .$exception->getStatusCode()." instanceof,但是有很多可能的错误会出现500错误,那么如何区分错误是不是其中之一呢?

进一步编辑:关于在底部打印“测试”的错误,我注意到当我执行$container-&gt;testError(); 时,我没有得到底部的“测试”错误,但是当我执行return $container; 时,我会这样做,即使这两个错误都是带有未定义变量的 ContextErrorException。

【问题讨论】:

    标签: symfony


    【解决方案1】:

    您最有可能在 Symfony 有机会启动之前遇到的 500 个错误。由于在这种情况下 Symfony 不会启动,因此它无法处理错误。要调试此类情况,您应该查看 Web 服务器(apache、ngnix 等)日志。

    【讨论】:

    • 感谢您迄今为止的帮助。据我所知,所有错误都是在 Symfony 启动后被捕获的,因为它们都以正常的 Symfony 格式显示,带有灰色背景消息和调试回溯。我在原始问题描述中添加了额外的测试结果和屏幕截图。也许这些可以提供帮助?
    【解决方案2】:

    我刚刚测试了捕获 500 个异常,它似乎工作正常。我想你可能有其他东西拦截异常?也许开始一个新项目,然后再试一次。

    我自己更喜欢订阅者界面:

    class ExceptionListener extends ContainerAware implements EventSubscriberInterface
    {
        public static function getSubscribedEvents()
        {
            return array(KernelEvents::EXCEPTION => array(
                array('doException', 200),
            ));
        }
        public function doException(GetResponseForExceptionEvent $doEvent)
        {
            $exception = $doEvent->getException();
    
            die('Exception caught ' . $exception->getStatusCode());
    
    cerad_core__exception_listener:
        class:   Cerad\Bundle\CoreBundle\EventListener\ExceptionListener
        tags:
            - { name: kernel.event_subscriber }
    

    请注意,您还可以将记录器配置为发送电子邮件。可能会更容易。

    http://symfony.com/doc/current/cookbook/logging/monolog_email.html

    @Ferhad 提出了一个很好的观点。一些(但不是全部)500 错误基本上会使 S2 应用程序崩溃。但我假设您收到的是默认的 S2 异常消息。

    【讨论】:

    • 感谢您迄今为止的帮助。我想让它继续通过听众,因为我的 Symfony2 知识仍处于起步阶段,除了 500 个错误之外,我的工作 80% 完美。我已经用额外的屏幕截图和测试结果更新了我的原始问题描述。你能看看这个,如果你有任何进一步的建议,请告诉我?我不太担心语法错误之类的事情。我希望这个处理程序能够捕获诸如未定义变量、尝试循环空数组、对非对象进行方法调用等错误。你知道:奇怪的生产问题。
    • 我只能说:祝你好运。由于您的 S2 知识仍处于起步阶段,因此使用提供的工具而不是自己制作可能更有意义。但这取决于你。我能够毫无问题地捕获未定义的变量。但是语法错误几乎肯定会是致命的。在将代码投入生产之前专注于测试代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-18
    • 2016-09-22
    • 2012-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    相关资源
    最近更新 更多