1

我的系统需要使用外部服务进行身份验证(以任何方式不受我的控制),并且身份验证需要非常短的序列中的两个 HTTP 请求(我在第一个请求中获得的令牌在 2 秒后过期,我必须使用它来完成认证过程)。

所以我基本上是这样做的:

// create client
$client        = HttpClient::create();
$baseUrl       = "https://example.com/webservice.php";
$username      = "foo";
$token         = "foobarbaz";

// first request
$tokenResponse = $client->request( Method::GET, $baseUrl . '?operation=getchallenge&username=' . $username );
$decoded       = $tokenResponse->toArray();

// second request
$loginResponse = $client->request( Method::POST, $this->baseUrl, [
                 'body' => [
                        'operation' => 'login',
                        'username'  => $username,
                        'accessKey' => md5( $decoded['result']['token'] . $token ),
                    ],
                ]
            );

$sessionData = $loginResponse->toArray();

这样做,我得到一个异常(TransportExceptionInterface):

无法向“ https://example.com/webservice.php ”的对等方发送数据

但是,如果我不使用相同的实例而是$client实例化一个新的($client2 = HttpClient::create();

我的猜测是,这与 HTTP 客户端使用的默认请求并发有关,但我检查了文档可用的选项HttpClientInterface但无论如何我都没有以不需要我的方式更改客户端行为创建一个新实例(也不是增加错误记录详细程度的方法)。

我安装了 cURL 扩展,所以正在创建的客户端是CurlHttpClient而不是NativeHttpClient.

有没有办法解决这个问题,而不必创建一个新的客户端实例?

4

1 回答 1

1

这是文档所说的。

即使在进行常规同步调用时,这种设计也允许在请求之间保持与远程主机的连接打开,通过节省重复的 DNS 解析、SSL 协商等来提高性能。为了利用所有这些设计优势,需要 cURL 扩展。

为了使用 php 流,示例说明您使用 NativeClient,如下所示:

use Symfony\Component\HttpClient\CurlHttpClient;
use Symfony\Component\HttpClient\NativeHttpClient;

// uses native PHP streams
$client = new NativeHttpClient();

// uses the cURL PHP extension
$client = new CurlHttpClient();

这样您就可以在没有框架的情况下选择特定的客户端,从而使您使用 curl 客户端。

获得令牌后,关闭连接并从同一个客户端创建一个新连接,这将确保您使用相同的 Client 对象但启动新的连接要求,这模仿了服务器进行身份验证所需的行为。

在解析正文之前检查服务器响应总是好的。请检查服务器是否已发送带有令牌的 200 响应并扩展您的逻辑。尝试捕获或检查标头始终是错误处理的奖励和良好实践。

于 2020-03-04T08:14:32.023 回答