feat : Decorator Http

This commit is contained in:
2025-09-07 10:15:57 +08:00
parent abb354ebe0
commit 04c4678e2e
9 changed files with 226 additions and 8 deletions

View File

@@ -45,7 +45,12 @@ class DecoratorController extends AbstractController
return (new AopService)->handle();
}
public function http()
/**
* http 装饰器
* @return array
*/
#[RequestMapping(path: 'http', methods: 'GET')]
public function http(): array
{
return (new HttpService)->handle();
}

View 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;
}

View 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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -11,12 +11,31 @@ declare(strict_types=1);
namespace App\Service\Test\Decorator;
use App\Interface\Test\Decorator\HttpClientInterface;
use App\Service\Test\TestBaseService;
use Hyperf\Di\Annotation\Inject;
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),
]);
}
}

View File

@@ -11,14 +11,16 @@ declare(strict_types=1);
*/
use App\Interface\Test\Adapter\CacheInterface;
use App\Interface\Test\Decorator\HttpClientInterface;
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\Decorator\Container\BasicFileLogger;
use App\Service\Test\Decorator\Container\CriticalLoggerDecorator;
use App\Service\Test\Decorator\Container\IpLoggerDecorator;
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;
return [
@@ -30,4 +32,10 @@ return [
$logger = make(IpLoggerDecorator::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]);
}
];

View File

@@ -48,5 +48,5 @@
装饰器模式在Java标准库中有广泛应用特别是I/O流处理部分(如BufferedInputStream装饰FileInputStream)。理解这种模式有助于编写更灵活、更易扩展的代码。
#### tips
`App\Service\Test\Decorator\ContainerService`
`App\Service\Test\Decorator\ContainerService`
`App\Aspect\Test\Decorator\Aop\CacheableAspect`

View File

@@ -24,7 +24,10 @@ Content-Type: application/x-www-form-urlencoded
### Decorator aop test
GET {{host}}/decorator/test/aop
GET {{host}}/decorator/test/aop?user_id=12
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