164 lines
4.3 KiB
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
|
|
);
|
|
}
|
|
}
|