Symfony FOSRestBundle 添加自定义 header 到响应
Symfony FOSRestBundle add custom header to response
我在 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
现在我想在我的回复中添加自定义 header 'X-Total-Found'。怎么做?
您依赖于 FOSRestBundle ViewListener,因此您的选择有限,例如无法传递自定义 header。为了实现你想要的,你需要从你的控制器调用 $this->handleView()
并传递给它一个有效的 View
实例。
您可以使用 View::create() 工厂方法或控制器 $this->view()
快捷方式。两者都将数据数组、状态代码和响应 headers 数组作为参数。然后,您可以在那里设置您的自定义 header,但您必须为每次调用都这样做。
您拥有的另一个更易于维护的选项是注册一个 on_kernel_response
事件 listener/subscriber 并以某种方式将您的自定义值 header 传递给它(您可以将其存储在例如请求属性)。
这是您的两个选择。你可能还有第三个,但我现在想不出来。
我运行进入同样的问题。我们想将分页元信息移动到 headers 并使响应不带信封(数据和元属性)。
我的环境
- Symfony 版本 5.2
- PHP 版本 8
- FOS 休息包
第 1 步:创建一个 object 来保存 header 信息
// 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);
}
}
}
我在 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
现在我想在我的回复中添加自定义 header 'X-Total-Found'。怎么做?
您依赖于 FOSRestBundle ViewListener,因此您的选择有限,例如无法传递自定义 header。为了实现你想要的,你需要从你的控制器调用 $this->handleView()
并传递给它一个有效的 View
实例。
您可以使用 View::create() 工厂方法或控制器 $this->view()
快捷方式。两者都将数据数组、状态代码和响应 headers 数组作为参数。然后,您可以在那里设置您的自定义 header,但您必须为每次调用都这样做。
您拥有的另一个更易于维护的选项是注册一个 on_kernel_response
事件 listener/subscriber 并以某种方式将您的自定义值 header 传递给它(您可以将其存储在例如请求属性)。
这是您的两个选择。你可能还有第三个,但我现在想不出来。
我运行进入同样的问题。我们想将分页元信息移动到 headers 并使响应不带信封(数据和元属性)。
我的环境
- Symfony 版本 5.2
- PHP 版本 8
- FOS 休息包
第 1 步:创建一个 object 来保存 header 信息
// 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);
}
}
}