【问题标题】:Symfony FOSRestBundle add custom header to responseSymfony FOSRestBundle 将自定义标头添加到响应
【发布时间】:2018-10-04 16:53:27
【问题描述】:

我在 Symfony 4 中使用 FOSRestBundle 到 API 项目。我使用注释,例如在控制器中

use FOS\RestBundle\Controller\Annotations as Rest;

/**
 * @Rest\Get("/api/user", name="index",)
 * @param UserRepository $userRepository
 * @return array
 */
public function index(UserRepository $userRepository): array
{
return ['status' => 'OK', 'data' => ['users' => $userRepository->findAll()]];
}

config/packages/fos_rest.yaml

fos_rest:
    body_listener: true
    format_listener:
        rules:
            - { path: '^/api', priorities: ['json'], fallback_format: json, prefer_extension: false }
    param_fetcher_listener: true
    view:
        view_response_listener: 'force'
        formats:
            json: true

现在我想在我的回复中添加自定义标题“X-Total-Found”。怎么做?

【问题讨论】:

    标签: symfony header fosrestbundle


    【解决方案1】:

    您依赖于 FOSRestBundle ViewListener,因此这为您提供了有限的选择,例如无法传递自定义标头。为了实现你想要的,你需要从你的控制器调用$this->handleView() 并传递一个有效的View 实例。

    您可以使用 View::create() 工厂方法或控制器 $this->view() 快​​捷方式。两者都将数据数组、状态代码和响应标头数组作为参数。然后,您可以在那里设置自定义标头,但您必须为每次调用都这样做。

    您拥有的另一个更易于维护的选项是注册一个on_kernel_response 事件侦听器/订阅者,并以某种方式将您的自定义标头的值传递给它(例如,您可以将其存储在请求属性中)。

    这是您拥有的两个选项。你可能有第三个,但我现在想不出。


    【讨论】:

    • 您好,谢谢您的回复。我不能使用 $this->view()->handleView() 因为它属于 Twig 而我没有安装 Twig。我认为最好的选择是按照您的建议注册侦听器。但我找到了其他方法,但我认为这不是一个好的解决方案。所以在return $users之前我加了header('X-Total-Count: '. count($users));
    • 是的,这有点老套,可能更难维护。
    • 顺便说一下,$this->view()$this->handleView() 不属于 Twig。这些是RestController Trait的方法,所以你可以使用它。
    • 好吧,我一定是搞错了。我尝试$view = $this->view($users, 200, ['X-Total-count' => count($users)]); $view->setFormat('json'); return $this->handleView($view); 但这会返回错误 500 并说返回必须是一个数组
    • 我可以得到那个堆栈跟踪吗?
    【解决方案2】:

    我遇到了同样的问题。我们想将分页元信息移动到标题中,并让响应不带信封(数据和元属性)。

    我的环境

    • Symfony 5.2 版
    • PHP 版本 8
    • FOS 休息包

    第 1 步:创建一个对象来保存标题信息

        // src/Rest/ResponseHeaderBag.php
        namespace App\Rest;
        
        /**
         * Store header information generated in the controller. This same
         * object is used in the response subscriber.
         * @package App\Rest
         */
        class ResponseHeaderBag
        {
            protected array $data = [];
        
            /**
             * @return array
             */
            public function getData(): array
            {
                return $this->data;
            }
        
            /**
             * @param array $data
             * @return ResponseHeaderBag
             */
            public function setData(array $data): ResponseHeaderBag
            {
                $this->data = $data;
                return $this;
            }
        
            public function addData(string $key, $datum): ResponseHeaderBag
            {
                $this->data[$key] = $datum;
                return $this;
            }
        }
    

    第 2 步:将 ResponseHeaderBag 注入到控制器操作中

     public function searchCustomers(
        ResponseHeaderBag $responseHeaderBag
    ): array {
       ...
       ...
       ...
       // replace magic strings and numbers with class constants and real values.
       $responseHeaderBag->add('X-Pagination-Count', 8392); 
       ...
       ...
       ...
    }
    

    第 3 步:注册订阅者并监听响应内核事件

        // config/services.yaml        
        App\EventListener\ResponseSubscriber:
          tags:
             - kernel.event_subscriber
    

    订阅者是监听事件的好方法。

        // src/EventListener/ResponseSubscriber
        namespace App\EventListener;
        
        use App\Rest\ResponseHeaderBag;
        use Symfony\Component\EventDispatcher\EventSubscriberInterface;
        use Symfony\Component\HttpKernel\Event\ResponseEvent;
        use Symfony\Component\HttpKernel\KernelEvents;
    
        class ResponseSubscriber implements EventSubscriberInterface
        {
            public function __construct(
                protected ResponseHeaderBag $responseHeaderBag
            ){
            }
    
            /**
             * @inheritDoc
             */
            public static function getSubscribedEvents()
            {
                return [
                    KernelEvents::RESPONSE => ['addAdditionalResponseHeaders']
                ];
            }
    
    
            /**
             * Add the response headers created elsewhere in the code.
             * @param ResponseEvent $event
             */
            public function addAdditionalResponseHeaders(ResponseEvent $event): void
            {
                $response = $event->getResponse();
                foreach ($this->responseHeaderBag->getData() as $key => $datum) {
                    $response->headers->set($key, $datum);
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-10
      • 2018-02-26
      • 2017-07-04
      • 1970-01-01
      • 2021-12-28
      • 2012-10-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多