php 如何在symfony5中将所有HttpRequest格式化为json?

qgzx9mmu  于 2023-11-16  发布在  PHP
关注(0)|答案(4)|浏览(171)

在symfony 5控制器中,我可以通过以下方式返回json响应:

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

字符串
然而,当我抛出一个HttpException时,我在开发和生产中都看到了默认的html错误页面。
我想创建一个restful的API,所以我想把所有的HTTP转换成JSON。
我想配置我所有的控制器,将它们的响应格式化为json。最多,我想添加一个异常处理程序,将异常转换为正确的消息。(在prod中,它应该有较少的信息,在dev中,它可能包含异常堆栈跟踪。)
我想我可以使用@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的以下回答:
您需要安装/启用序列化器组件,
但我不知道这意味着什么
在dev和prod中,我得到了这些html视图,而不是json响应:

prod

x1c 0d1x的数据

开发者


txu3uszq

txu3uszq1#

原来我所缺少的就是安装symfony docs中指出的序列化器包:

composer require symfony/serializer-pack

字符串
之后,我的异常会被渲染为json fine。

fae0ux8s

fae0ux8s2#

创建事件侦听器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);
        }
    }
}

vybvopom

vybvopom3#

软件包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());
    }
}

字符串

bqujaahr

bqujaahr4#

在API开发环境中,最简单和最有效的方法是修改Default ErrorController。这允许您根据应用程序中使用的JSON Api标准(示例中为Jsend)格式化错误输出。
请参阅此处的文档
首先创建ApiErrorController:

php bin/console make:controller --no-template ApiErrorController

字符串
第二个设置框架配置使用它:

framework: 
...

error_controller: App\Controller\ApiErrorController::show


第三次编辑ApiErrorController:

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Psr\Log\LoggerInterface;
use Throwable;

class ApiErrorController extends AbstractController
{
    #[Route('/api/error', name: 'app_api_error')]
    public function show(Throwable $exception, LoggerInterface $logger): JsonResponse
    {
       
        //Transform Warning status code from 0 to 199 
        $statusCode = (!$exception->getCode() || $exception->getCode()==0)? 199 : $exception->getCode() ;
        
        //Log the error
        if($statusCode<=199){ 
            $logger->warning($exception->getMessage());
        } else {
            $logger->error($exception->getMessage());
        }

        //Prepare basic data output coforming on JSend STD.
        $data = [
            'status'=>($statusCode>=400)? 'error' : 'fail',
            'message' => $exception->getMessage(),
        ];

        //If Dev add trace
        if ($this->getParameter('kernel.environment') === 'dev') {
            $data['trace'] = $exception->getTrace();
        }

        //return Json
        return $this->json($data, $statusCode);
    }
}

相关问题