简体   繁体   中英

Symfony: How to return a JSON response from a Before Filter (Listener)?

From following this example I have managed to set up the below Listener/Before Filter to parse all requests to my API endpoint (ie. /api/v1) before any controller actions are processed. This is used to validate the request type and to throw an error if certain conditions are not met.

I would like to differentiate the error response based on the applications environment state. If we are in development or testing, I simply want to throw the error encountered. Alternatively, if in production mode I want to return the error as a JSON response. Is this possible? If not, how could I go about something similar?

I'm using Symfony v3.1.*, if that makes any difference.

namespace AppBundle\EventListener;

use AppBundle\Interfaces\ApiAuthenticatedController;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

class ApiBeforeListener
{
    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    protected $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    /**
     * Validates a request for API resources before serving content
     *
     * @param \Symfony\Component\HttpKernel\Event\FilterControllerEvent $event
     * @return mixed
     */
    public function onKernelController(FilterControllerEvent $event)
    {
        $controller = $event->getController();

        if (!is_array($controller))
            return;

        if ($controller[0] instanceof ApiAuthenticatedController) {

            $headers = $event->getRequest()->headers->all();

            // only accept ajax requests
            if(!isset($headers['x-requested-with'][0]) || strtolower($headers['x-requested-with'][0]) != 'xmlhttprequest') {

                $error = new AccessDeniedHttpException('Unsupported request type.');

                if (in_array($this->container->getParameter("kernel.environment"), ['dev', 'test'], true)) {
                    throw $error;
                } else {
                    // return json response here for production environment
                    // 
                    // For example:
                    // 
                    // header('Content-Type: application/json');
                    // 
                    // return json_encode([
                    //  'code'    => $error->getCode(),
                    //  'status'  => 'error',
                    //  'message' => $error->getMessage()
                    // ]);
                }
            }
        }
    }

}

Unlike most events, the FilterControllerEvent does not allow you to return a response object. Be nice if it did but oh well.

You have two basic choices.

The best one is to simply throw an exception and then add an exception listener. The exception listener can then return a JsonResponse based on the environment.

Another possibility to to create a controller which only returns your JsonResponse then use $event->setController($jsonErrorController) to point to it.

But I think throwing an exception is probably your best bet.

More details here: http://symfony.com/doc/current/reference/events.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM