如何在 symfony 5 中将所有 Http 异常格式化为 json?

How to format all HttpExceptions as json in symfony5?

在 symfony5 控制器中,我可以 return json 通过以下方式响应:

 return $this->json(['key' => 'content');

然而,当我抛出 HttpException 时,我在开发和生产中看到了默认的 html 错误页面。

我想创建一个restfulapi,所以我想把所有的HttpExceptions都转换成json。

我想将我所有的控制器配置为将它们的响应格式化为 json。至多,我想添加一个异常处理程序,将异常处理程序转换为正确的消息。 (在产品中它应该包含较少的信息,在开发中它可能包含异常堆栈跟踪。)

我怎样才能做到这一点?我以为我可以使用 @Route 注释的 format 选项,但它不起作用。

这是我的示例控制器:

<?php declare(strict_types=1);

namespace App\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;

class StatusController extends AbstractController
{
    /**
     * @Route("/status", name="status", format="json")
     * @Template
     * @return JsonResponse
     */
    public function status()
    {
        if (true) {
            // this will render as html, how to serialize it as json?
            throw new NotFoundHttpException("This is an example");
        }


        $ok = new \stdClass();
        $ok->status = "OK";

        return $this->json($ok);
    }
}

在寻找这个时我遇到了 this PR 这似乎实现了我想要做的事情,但我不确定我错过了什么。

the symfony blog 我发现 Yonel Ceruto 的回答如下

you will need to install/enable the serializer component,

但我不知道这意味着什么。


在开发和生产中,我得到了这些 html 视图而不是 json 响应:

产品

开发

原来我所缺少的只是安装序列化程序包,正如 symfony docs:

中指出的那样
composer require symfony/serializer-pack

之后,我的异常呈现为 json 正常。

symfony/serializer-pack 在我的环境中不工作。

最后我创建了一个 ErrorController 回复 json .

namespace App\Controller;

use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Throwable;

class JsonErrorController
{
    public function show(Throwable $exception, LoggerInterface $logger)
    {
        return new JsonResponse($exception->getMessage(), $exception->getCode());
    }
}

创建事件侦听器ExceptionListener 并在 services.yml

中注册
services:
    ...
    App\EventListener\ExceptionListener:
        tags:
            - { name: kernel.event_listener, event: kernel.exception }

ExceptionLister.php

// src/EventListener/ExceptionListener.php
namespace App\EventListener;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

class ExceptionListener
{
    public function onKernelException(ExceptionEvent $event)
    {
        // You get the exception object from the received event
        $exception = $event->getThrowable();
        // Get incoming request
        $request   = $event->getRequest();

        // Check if it is a rest api request
        if ('application/json' === $request->headers->get('Content-Type'))
        {

            // Customize your response object to display the exception details
            $response = new JsonResponse([
                'message'       => $exception->getMessage(),
                'code'          => $exception->getCode(),
                'traces'        => $exception->getTrace()
            ]);

            // HttpExceptionInterface is a special type of exception that
            // holds status code and header details
            if ($exception instanceof HttpExceptionInterface) {
                $response->setStatusCode($exception->getStatusCode());
                $response->headers->replace($exception->getHeaders());
            } else {
                $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
            }

            // sends the modified response object to the event
            $event->setResponse($response);
        }
    }
}