WokerTask/extend/IFlytek/Xfyun/Core/HttpClient.php

164 lines
4.3 KiB
PHP

<?php
/**
* Copyright 1999-2021 iFLYTEK Corporation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace IFlytek\Xfyun\Core;
/**
* Http客户端
*
* @author guizheng@iflytek.com
*/
use Exception;
use GuzzleHttp\Psr7\Response;
use IFlytek\Xfyun\Core\Handler\Guzzle7HttpHandler;
use IFlytek\Xfyun\Core\Traits\SignTrait;
use IFlytek\Xfyun\Core\Traits\DecideRetryTrait;
use IFlytek\Xfyun\Core\Handler\HttpHandlerFactory;
use Psr\Http\Message\RequestInterface;
use GuzzleHttp\Psr7\Utils;
class HttpClient
{
use SignTrait;
use DecideRetryTrait;
const MAX_DELAY_MICROSECONDS = 60000000;
/**
* @var Guzzle7HttpHandler
*/
private $httpHandler;
/**
* @var array 要添加的头部信息
*/
private $httpHeaders;
/**
* @var int 超时时间
*/
private $requestTimeout;
/**
* @var int 重试次数
*/
private $retries;
/**
* @var int 重试次数
*/
private $decideRetryFunction;
/**
* @var int 重试次数
*/
private $delayFunction;
/**
* @var int 重试次数
*/
private $calcDelayFunction;
public function __construct($config)
{
$config += [
'httpHandler' => null,
'httpHeaders' => [],
'requestTimeout' => 3000,
'retries' => 3,
'decideRetryFunction' => null,
'delayFunction' => null,
'calcDelayFunction' => null
];
$this->httpHandler = $config['httpHandler'] ?: HttpHandlerFactory::build();
$this->httpHeaders = $config['httpHeaders'];
$this->retries = $config['retries'];
$this->decideRetryFunction = $config['decideRetryFunction'] ?: $this->getDecideRetryFunction();
$this->calcDelayFunction = $config['calcDelayFunction'] ?: [$this, 'calculateDelay'];
$this->delayFunction = $config['delayFunction'] ?: static function ($delay) {
usleep($delay);
};
}
/**
* 发送请求,并接受返回
*
* @param RequestInterface $request
* @param array $options 请求的配置参数
* @return Response
* @throws Exception
*/
public function sendAndReceive(RequestInterface $request, array $options = [])
{
try {
$delayFunction = $this->delayFunction;
$calcDelayFunction = $this->calcDelayFunction;
$retryAttempt = 0;
while (true) {
try {
return call_user_func_array($this->httpHandler, [$this->applyHeaders($request), $options]);
} catch (Exception $exception) {
if ($this->decideRetryFunction) {
if (!call_user_func($this->decideRetryFunction, $exception)) {
throw $exception;
}
}
if ($retryAttempt >= $this->retries) {
break;
}
$delayFunction($calcDelayFunction($retryAttempt));
$retryAttempt++;
}
}
throw $exception;
} catch (Exception $ex) {
throw $ex;
}
}
/**
* 将头部信息添加到请求对象中
*
* @param $request 请求对象
* @return RequestInterface
*/
private function applyHeaders($request)
{
return Utils::modifyRequest($request, ['set_headers' => $this->httpHeaders]);
}
/**
* 根据重试次数计算下次重试延迟时间
*
* @param int $attempt 重试次数
* @return int
*/
public static function calculateDelay($attempt)
{
return min(
mt_rand(0, 1000000) + (pow(2, $attempt) * 1000000),
self::MAX_DELAY_MICROSECONDS
);
}
}