feat : Decorator Http
This commit is contained in:
@@ -45,7 +45,12 @@ class DecoratorController extends AbstractController
|
|||||||
return (new AopService)->handle();
|
return (new AopService)->handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function http()
|
/**
|
||||||
|
* http 装饰器
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
#[RequestMapping(path: 'http', methods: 'GET')]
|
||||||
|
public function http(): array
|
||||||
{
|
{
|
||||||
return (new HttpService)->handle();
|
return (new HttpService)->handle();
|
||||||
}
|
}
|
||||||
|
|||||||
21
app/Interface/Test/Decorator/HttpClientInterface.php
Normal file
21
app/Interface/Test/Decorator/HttpClientInterface.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Interface\Test\Decorator;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
interface HttpClientInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 请求装饰器接口
|
||||||
|
* @param string $method
|
||||||
|
* @param string $url
|
||||||
|
* @param array $options
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function request(
|
||||||
|
string $method,
|
||||||
|
string $url,
|
||||||
|
array $options = []
|
||||||
|
): mixed;
|
||||||
|
}
|
||||||
28
app/Lib/Request/GuzzleHttpClient.php
Normal file
28
app/Lib/Request/GuzzleHttpClient.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Lib\Request;
|
||||||
|
|
||||||
|
use App\Interface\Test\Decorator\HttpClientInterface;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
class GuzzleHttpClient implements HttpClientInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $method
|
||||||
|
* @param string $url
|
||||||
|
* @param array $options
|
||||||
|
* @return ResponseInterface
|
||||||
|
* @throws GuzzleException
|
||||||
|
*/
|
||||||
|
public function request(
|
||||||
|
string $method,
|
||||||
|
string $url,
|
||||||
|
array $options = []
|
||||||
|
): ResponseInterface
|
||||||
|
{
|
||||||
|
$client = new Client();
|
||||||
|
return $client->request($method, $url, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This service file is part of item.
|
||||||
|
*
|
||||||
|
* @author ctexthuang
|
||||||
|
* @contact ctexthuang@qq.com
|
||||||
|
* @web_site https://ctexthuang.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Service\Test\Decorator\Http;
|
||||||
|
|
||||||
|
use App\Interface\Test\Decorator\HttpClientInterface;
|
||||||
|
use App\Interface\Test\Decorator\LoggerInterface;
|
||||||
|
use Exception;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
class LoggableHttpClientService implements HttpClientInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var HttpClientInterface
|
||||||
|
*/
|
||||||
|
private HttpClientInterface $httpClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
private LoggerInterface $logger;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
HttpClientInterface $httpClient,
|
||||||
|
LoggerInterface $logger,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->httpClient = $httpClient;
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $method
|
||||||
|
* @param string $url
|
||||||
|
* @param array $options
|
||||||
|
* @return ResponseInterface|false
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function request(string $method, string $url, array $options = []): ResponseInterface|false
|
||||||
|
{
|
||||||
|
$this->logger->log("Sending {{$method}} request to {{$url}}");
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $this->httpClient->request($method, $url, $options);
|
||||||
|
$this->logger->log("Request to {{$url}} completed successfully");
|
||||||
|
return $response;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->logger->error("Request to {{$url} failed: {{$e->getMessage()}}}");
|
||||||
|
// throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This service file is part of item.
|
||||||
|
*
|
||||||
|
* @author ctexthuang
|
||||||
|
* @contact ctexthuang@qq.com
|
||||||
|
* @web_site https://ctexthuang.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Service\Test\Decorator\Http;
|
||||||
|
|
||||||
|
use App\Interface\Test\Decorator\HttpClientInterface;
|
||||||
|
use App\Interface\Test\Decorator\LoggerInterface;
|
||||||
|
use Exception;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
class RetryableHttpClientService implements HttpClientInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 请求接口注入
|
||||||
|
* @var HttpClientInterface
|
||||||
|
*/
|
||||||
|
protected HttpClientInterface $httpClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志接口注入
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
protected LoggerInterface $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大重试
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private int $maxRetries;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
HttpClientInterface $httpClient,
|
||||||
|
LoggerInterface $logger,
|
||||||
|
int $maxRetries = 3
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->httpClient = $httpClient;
|
||||||
|
$this->maxRetries = $maxRetries;
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $method
|
||||||
|
* @param string $url
|
||||||
|
* @param array $options
|
||||||
|
* @return false|ResponseInterface
|
||||||
|
*/
|
||||||
|
public function request(string $method, string $url, array $options = []): ResponseInterface|false
|
||||||
|
{
|
||||||
|
var_dump('maxRetries:'.$this->maxRetries);
|
||||||
|
$retryCount = 0;
|
||||||
|
|
||||||
|
while ($retryCount < $this->maxRetries) {
|
||||||
|
try {
|
||||||
|
return $this->httpClient->request($method, $url, $options);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->logger->error('重试请求'.$url.':第'.$retryCount.'次'.$e->getMessage());
|
||||||
|
$retryCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,12 +11,31 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Service\Test\Decorator;
|
namespace App\Service\Test\Decorator;
|
||||||
|
|
||||||
|
use App\Interface\Test\Decorator\HttpClientInterface;
|
||||||
use App\Service\Test\TestBaseService;
|
use App\Service\Test\TestBaseService;
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
|
|
||||||
class HttpService extends TestBaseService
|
class HttpService extends TestBaseService
|
||||||
{
|
{
|
||||||
public function handle()
|
/**
|
||||||
|
* @var HttpClientInterface
|
||||||
|
*/
|
||||||
|
#[Inject]
|
||||||
|
protected HttpClientInterface $httpClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function handle(): array
|
||||||
{
|
{
|
||||||
return $this->return->success();
|
$response = $this->httpClient->request('GET','https://api.example.com/data',[
|
||||||
|
'timeout' => 5
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!$response) return $this->return->error();
|
||||||
|
|
||||||
|
return $this->return->success('请求成功',[
|
||||||
|
'body' => json_decode($response->getBody()->getContents(), true),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,14 +11,16 @@ declare(strict_types=1);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use App\Interface\Test\Adapter\CacheInterface;
|
use App\Interface\Test\Adapter\CacheInterface;
|
||||||
|
use App\Interface\Test\Decorator\HttpClientInterface;
|
||||||
use App\Interface\Test\Decorator\LoggerInterface;
|
use App\Interface\Test\Decorator\LoggerInterface;
|
||||||
use App\Service\Test\Adapter\Cache\FileCacheAdapter;
|
use App\Lib\Request\GuzzleHttpClient;
|
||||||
use App\Service\Test\Adapter\Cache\RedisCacheService;
|
use App\Service\Test\Adapter\Cache\RedisCacheService;
|
||||||
use App\Service\Test\Decorator\Container\BasicFileLogger;
|
use App\Service\Test\Decorator\Container\BasicFileLogger;
|
||||||
use App\Service\Test\Decorator\Container\CriticalLoggerDecorator;
|
use App\Service\Test\Decorator\Container\CriticalLoggerDecorator;
|
||||||
use App\Service\Test\Decorator\Container\IpLoggerDecorator;
|
use App\Service\Test\Decorator\Container\IpLoggerDecorator;
|
||||||
use App\Service\Test\Decorator\Container\TimestampLoggerDecorator;
|
use App\Service\Test\Decorator\Container\TimestampLoggerDecorator;
|
||||||
use Hyperf\Logger\LoggerFactory;
|
use App\Service\Test\Decorator\Http\LoggableHttpClientService;
|
||||||
|
use App\Service\Test\Decorator\Http\RetryableHttpClientService;
|
||||||
use function Hyperf\Support\make;
|
use function Hyperf\Support\make;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@@ -30,4 +32,10 @@ return [
|
|||||||
$logger = make(IpLoggerDecorator::class, ['logger' => $logger]);
|
$logger = make(IpLoggerDecorator::class, ['logger' => $logger]);
|
||||||
return make(CriticalLoggerDecorator::class, ['logger' => $logger]);
|
return make(CriticalLoggerDecorator::class, ['logger' => $logger]);
|
||||||
},
|
},
|
||||||
|
HttpClientInterface::class => function () {
|
||||||
|
$client = make(GuzzleHttpClient::class);
|
||||||
|
$logger = make(BasicFileLogger::class);
|
||||||
|
$client = make(RetryableHttpClientService::class,['httpClient' => $client , 'logger' => $logger , 'maxRetries' => 2]);
|
||||||
|
return make(LoggableHttpClientService::class,['httpClient' => $client , 'logger' => $logger]);
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -48,5 +48,5 @@
|
|||||||
装饰器模式在Java标准库中有广泛应用,特别是I/O流处理部分(如BufferedInputStream装饰FileInputStream)。理解这种模式有助于编写更灵活、更易扩展的代码。
|
装饰器模式在Java标准库中有广泛应用,特别是I/O流处理部分(如BufferedInputStream装饰FileInputStream)。理解这种模式有助于编写更灵活、更易扩展的代码。
|
||||||
|
|
||||||
#### tips
|
#### tips
|
||||||
`App\Service\Test\Decorator\ContainerService`
|
`App\Service\Test\Decorator\ContainerService`
|
||||||
`App\Aspect\Test\Decorator\Aop\CacheableAspect`
|
`App\Aspect\Test\Decorator\Aop\CacheableAspect`
|
||||||
@@ -24,7 +24,10 @@ Content-Type: application/x-www-form-urlencoded
|
|||||||
|
|
||||||
|
|
||||||
### Decorator aop test
|
### Decorator aop test
|
||||||
GET {{host}}/decorator/test/aop
|
GET {{host}}/decorator/test/aop?user_id=12
|
||||||
Content-Type: application/x-www-form-urlencoded
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
user_id=12
|
|
||||||
|
### Decorator http test
|
||||||
|
GET {{host}}/decorator/test/http
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
Reference in New Issue
Block a user