如何在 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);
}
}
}
在 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);
}
}
}