Symfony FOSRestBundle为响应添加自定义标头

时间:2018-04-24 12:18:25

标签: symfony header fosrestbundle

我在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()]];
}

配置/包/ 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'。怎么做?

2 个答案:

答案 0 :(得分:1)

您依赖于FOSRestBundle ViewListener,因此为您提供了有限的选项,例如无法传递自定义标头。为了达到您想要的效果,您需要从控制器中调用$this->handleView()并将其传递给有效的View实例。

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

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

这是您拥有的两个选项。你可能有第三个,但我不能在一分钟拿出来。

答案 1 :(得分:0)

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

我的环境

  • 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);
            }
        }
    }