将请求 header 与 HTTP 客户端一起使用到外部 Api 服务器

Use a request header with HTTP Client to external Api server

考虑以下对 Symfony 控制器的请求:

http http://127.0.0.1:8000/index x-token:1000
#[Route('/index', name: 'index')]
public function index(HttpClientInterface $client, Request $request): Response
{
    $client->request('GET', 'http://0.0.0.0:3001', ['headers' => ['x-token' => $request->headers->get('x-token')]]);
    return new JsonResponse();
}

此代码片段是在控制器中使用的最小示例。控制器接受请求,并使用 x-token header 对第 3 方进行身份验证 Api(此处:localhost:3001)。

有没有办法使这个过程自动化?所以基本上 - 监听传入的请求并将 x-token header 注入 Symfony 中的特定 Scoped Client or the default client

目标是,不是在每次使用 Http 客户端时都这样做,而是配置客户端服务。

客户端将在整个代码库中使用,而不仅仅是在这个最小示例中的控制器中。

我知道我可以使用 Service Decoration 并扩展正在使用的客户端。我无法连接点并使它起作用。

您尝试过使用 symfony kernel events 吗?

首先,如果您要调用一些第 3 方 api,我建议您在基础设施层创建一个单独的 class,例如 MyApiProvider。直接从你的控制器使用 HttpClient 并不聪明,因为你可能还想调整一些东西(例如 api 主机等)。所以它看起来像这样:

<?php

namespace App\Infrastructure\Provider;

class MyApiProvider
{
    // Of course, this also be better configurable via your .env file
    private const HOST = 'http://0.0.0.0:3001';

    private HttpClientInterface $client;

    private ?string $token = null;

    public function __construct(HttpClientInterface $client)
    {
        $this->client = $client;
    }

    public function setToken(string $token): void
    {
        $this->token = $token;
    }


    public function getSomething(): array
    {
        $response = $this->client->request(
            'GET',
            self::HOST,
            ['headers' => $this->getHeaders()]
        );

        return $response->toArray();
    }

    private function getHeaders(): array
    {
        $headers = [];
        if ($this->token !== null) {
            $headers['x-token'] = $this->token;
        }

        return $headers;
    }
}

然后您需要使用 symfony 的 kernel.request 事件从请求中向您的提供商注入令牌:

<?php

namespace App\Event;

use Symfony\Component\HttpKernel\Event\KernelEvent;

class RequestTokenEventListener
{
    private MyApiProvider $provider;

    public function __construct(MyApiProvider $provider)
    {
        $this->provider = $provider;
    }

    public function onKernelController(KernelEvent $event): void
    {
        $request = $event->getRequest();
        $token = $request->headers->get('x-token');

        if ($token !== null) {
            $this->provider->setToken($token);
        }
    }
}

最后是你的控制器:

#[Route('/index', name: 'index')]
public function index(MyApiProvider $provider): Response
{
    $provider->getSomething();

    return new JsonResponse();
}

因此,如果令牌已通过,您的提供商将在每个请求期间拥有令牌上下文。