Symfony2内核异常事件在生产模式下不处理致命错误异常

问题描述 投票:3回答:2

我为异常处理做了一个监听器。 以下是我的代码

services.yml

kernel.listener.prod_exception_listener:
    class: MyBundle\Listener\ExceptionListener
    tags:
        - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }

ExceptionListener.php

<?php
namespace MyBundle\Listener;

use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

class ExceptionListener
{
    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        // no fatal exception goes here others are coming in this function
        // like 403,404,500 are coming in this block

    }
}

我需要为生产模式中的致命异常做些什么额外的工作? 因为在开发模式中,致命错误正在听众中出现。

symfony exception-handling symfony-2.5
2个回答
1
投票

我在services.yml中通过以下方式解决了这个问题

api_exception_subscriber:
    class: AppBundle\EventListener\ApiExceptionSubscriber
    arguments: ['%kernel.debug%', '@api.response_factory', '@logger']
    tags:
        - { name: kernel.event_subscriber }
api.response_factory:
    class: AppBundle\Api\ResponseFactory

我的回复工厂看起来像:

<?php

namespace AppBundle\Api;

use Symfony\Component\HttpFoundation\JsonResponse;

class ResponseFactory
{
    public function createResponse(ApiProblem $apiProblem)
    {
        $data = $apiProblem->toArray();

        $response = new JsonResponse(
            $data,
            $apiProblem->getStatusCode()
        );
        $response->headers->set('Content-Type', 'application/json');

        return $response;
    }
} 

和Api订阅类

<?php

namespace AppBundle\EventListener;

use AppBundle\Api\ApiProblem;
use AppBundle\Api\ApiProblemException;
use AppBundle\Api\ResponseFactory;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

class ApiExceptionSubscriber implements EventSubscriberInterface
{
    private $debug;

    private $responseFactory;

    private $logger;

    public function __construct($debug, ResponseFactory $responseFactory, LoggerInterface $logger)
    {
        $this->debug = $debug;
        $this->responseFactory = $responseFactory;
        $this->logger = $logger;
    }

    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        // only reply to /api URLs
        if (strpos($event->getRequest()->getPathInfo(), '/api') !== 0) {
            return;
        }

        $e = $event->getException();

        $statusCode = $e instanceof HttpExceptionInterface ? $e->getStatusCode() : 500;

        // allow 500 errors to be thrown
        if ($this->debug && $statusCode >= 500) {
            return;
        }

        $this->logException($e);

        if ($e instanceof ApiProblemException) {
            $apiProblem = $e->getApiProblem();
        } else {


            $apiProblem = new ApiProblem(
                $statusCode
            );

            /*
             * If it's an HttpException message (e.g. for 404, 403),
             * we'll say as a rule that the exception message is safe
             * for the client. Otherwise, it could be some sensitive
             * low-level exception, which should *not* be exposed
             */
            if ($e instanceof HttpExceptionInterface) {
                $apiProblem->set('detail', $e->getMessage());
            }
        }

        $response = $this->responseFactory->createResponse($apiProblem);

        $event->setResponse($response);
    }

    public static function getSubscribedEvents()
    {
        return array(
            KernelEvents::EXCEPTION => 'onKernelException'
        );
    }

    /**
     * Adapted from the core Symfony exception handling in ExceptionListener
     *
     * @param \Exception $exception
     */
    private function logException(\Exception $exception)
    {
        $message = sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine());
        $isCritical = !$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500;
        $context = array('exception' => $exception);
        if ($isCritical) {
            $this->logger->critical($message, $context);
        } else {
            $this->logger->error($message, $context);
        }
    }
}

1
投票

我通过重写Kernel :: handle来手动调用ExceptionListener来处理这个问题

public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true): Response
{
    try {
        return parent::handle($request, $type, $catch);
    } catch (\Exception $exception) {
        throw new \Exception("There was an issue booting the framework");
    } catch (\Throwable $throwable) {
        $exception = new FatalThrowableError($throwable);

        $event = new ExceptionEvent($this, $request, $type, $exception);
        /** @var ExceptionListener $exceptionListener */
        $exceptionListener = $this->container->get(ExceptionListener::class);
        $exceptionListener->onKernelException($event);

        return $event->getResponse();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.