PHP-Guzzle中间件

问题描述 投票:0回答:2

我正在使用Pole Emploi的API,但是25分钟后当我的令牌过期时,我遇到401错误。

[我正在寻找一种获取新令牌并重试请求的方法,但是我没有办法了解中间件的工作方式,以及是否应根据需要使用中间件。

在Guzzle的文档中,这样写:

中间件函数返回一个接受下一个要调用的处理程序的函数。然后,此返回的函数返回充当组合处理程序的另一个函数-它接受请求和选项,并返回通过响应实现的promise。您组成的中间件可以修改请求,添加自定义请求选项以及修改下游处理程序返回的promise。

这是来自docs的示例代码:

use Psr\Http\Message\RequestInterface;

function my_middleware()
{
    return function (callable $handler) {
        return function (RequestInterface $request, array $options) use ($handler) {
            return $handler($request, $options);
        };
    };
}

所以我认为我需要管理“承诺”以查看其HTTP代码是否为401,然后获取一个新令牌并重试该请求?

我迷路了,所以如果有人可以用不同的词来解释这个逻辑,我将不胜感激:)

谢谢你。

php http middleware guzzle
2个回答
0
投票

我不建议您这样做,因为调试您的应用程序可能会变得很麻烦,而且据我所知,Guzzle确实不允许中间件访问客户端。无论如何,您都可以使用Promises来解决问题。如果您是我,我会在其他请求之前刷新令牌,或者定期刷新。如果您一个接一个地发出请求,可能会很好,但是在Pool中,这将成为一场噩梦,因为您最终可能会导致脚本获取令牌的次数过多,然后某些请求最终会使用过期的令牌。

无论如何,这是一个粗糙的示例:

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;

function my_middleware()
{
    return function (callable $handler) {
        return function (RequestInterface $request, array $options) use ($handler) {
            /**
             * @var $promise \GuzzleHttp\Promise\Promise
             */
            $promise = $handler($request, $options);

            return $promise->then(
                function (ResponseInterface $response) use ($request, $options) {
                    if ($response->getStatusCode() === 404) {
                        var_dump($response->getStatusCode());
                        var_dump(strlen($response->getBody()));

                        // Pretend we are getting new token key here
                        $client = new Client();
                        $key = $client->get('https://www.iana.org/domains/reserved');

                        // Then we modify the failed request. For your case you use ->withHeader() to change the
                        // Authorization header with your token.
                        $uri = $request->getUri();
                        $uri = $uri->withHost('google.com')->withPath('/');

                        // New instance of Request
                        $request = $request->withUri($uri);

                        // Send the request again with our new header/URL/whatever
                        return $client->sendAsync($request, $options);
                    }

                    return $response;
                }
            );
        };
    };
}

$handlerStack = HandlerStack::create();
$handlerStack->push(my_middleware());

$client = new Client([
    'base_uri' => 'https://example.org',
    'http_errors' => false,
    'handler' => $handlerStack
]);

$options = [];

$response = $client->request('GET', '/test', $options);

var_dump($response->getStatusCode());
var_dump(strlen($response->getBody()));
echo $response->getBody();

0
投票

并不需要那么困难,添加一个负责该工作的处理程序以及过期的缓存。

如果您不使用缓存,那么我想您可以将其与时间戳一起保存到文件中,以便在提取时进行检查。

class AuthenticationHandler
{
    private $username;
    private $password;
    private $token_name = 'access_token';

    public function __construct($username, $password)
    {
        $this->username = $username;
        $this->password = $password;
    }

    public function __invoke(callable $handler)
    {
        return function (RequestInterface $request, array $options) use ($handler) {
            if (is_null($token = Cache::get($this->token_name))) {
                $response = $this->getJWT();
                Cache::put($this->token_name, $token = $response->access_token, floor($response->expires_in));
            }

            return $handler(
                $request->withAddedHeader('Authorization', 'Bearer '.$token)
                    ->withAddedHeader('Api-Key', $this->api_key), $options
                );
        };
    }

    private function getJWT()
    {
        $response = (new Client)->request('POST', 'new/token/url', [
            'form_params' => [
                'grant_type' => 'client_credentials',
                'username' => $this->username,
                'password' => $this->password,
            ],
        ]);
        return json_decode($response->getBody());
    }
}

然后使用它:

$stack = HandlerStack::create(new CurlHandler());
$stack->push(new AuthenticationHandler('username', 'password'));
$client = new GuzzleHttp\Client([
    'base_uri' => 'https://api.com',
    'handler' => $stack,
]);

现在,您将始终拥有有效的令牌,并且您将不必再担心它。

© www.soinside.com 2019 - 2024. All rights reserved.