From 04c4678e2e3369aa1d9d2f67c9f6d0d539006065 Mon Sep 17 00:00:00 2001 From: ctexthuang Date: Sun, 7 Sep 2025 10:15:57 +0800 Subject: [PATCH] feat : Decorator Http --- app/Controller/Test/DecoratorController.php | 7 +- .../Test/Decorator/HttpClientInterface.php | 21 ++++++ app/Lib/Request/GuzzleHttpClient.php | 28 ++++++++ .../Http/LoggableHttpClientService.php | 62 ++++++++++++++++ .../Http/RetryableHttpClientService.php | 72 +++++++++++++++++++ app/Service/Test/Decorator/HttpService.php | 23 +++++- config/autoload/dependencies.php | 12 +++- document/decorator.md | 2 +- request/test.http | 7 +- 9 files changed, 226 insertions(+), 8 deletions(-) create mode 100644 app/Interface/Test/Decorator/HttpClientInterface.php create mode 100644 app/Lib/Request/GuzzleHttpClient.php create mode 100644 app/Service/Test/Decorator/Http/LoggableHttpClientService.php create mode 100644 app/Service/Test/Decorator/Http/RetryableHttpClientService.php diff --git a/app/Controller/Test/DecoratorController.php b/app/Controller/Test/DecoratorController.php index 93f965e..4dfd4ea 100644 --- a/app/Controller/Test/DecoratorController.php +++ b/app/Controller/Test/DecoratorController.php @@ -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(); } diff --git a/app/Interface/Test/Decorator/HttpClientInterface.php b/app/Interface/Test/Decorator/HttpClientInterface.php new file mode 100644 index 0000000..fdd412e --- /dev/null +++ b/app/Interface/Test/Decorator/HttpClientInterface.php @@ -0,0 +1,21 @@ +request($method, $url, $options); + } +} \ No newline at end of file diff --git a/app/Service/Test/Decorator/Http/LoggableHttpClientService.php b/app/Service/Test/Decorator/Http/LoggableHttpClientService.php new file mode 100644 index 0000000..2f215c9 --- /dev/null +++ b/app/Service/Test/Decorator/Http/LoggableHttpClientService.php @@ -0,0 +1,62 @@ +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; + } +} \ No newline at end of file diff --git a/app/Service/Test/Decorator/Http/RetryableHttpClientService.php b/app/Service/Test/Decorator/Http/RetryableHttpClientService.php new file mode 100644 index 0000000..f0b842e --- /dev/null +++ b/app/Service/Test/Decorator/Http/RetryableHttpClientService.php @@ -0,0 +1,72 @@ +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; + } +} \ No newline at end of file diff --git a/app/Service/Test/Decorator/HttpService.php b/app/Service/Test/Decorator/HttpService.php index 055f86d..8c13577 100644 --- a/app/Service/Test/Decorator/HttpService.php +++ b/app/Service/Test/Decorator/HttpService.php @@ -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), + ]); } } \ No newline at end of file diff --git a/config/autoload/dependencies.php b/config/autoload/dependencies.php index 39329e6..67dbf32 100644 --- a/config/autoload/dependencies.php +++ b/config/autoload/dependencies.php @@ -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]); + } ]; diff --git a/document/decorator.md b/document/decorator.md index 12c5278..79e5d86 100644 --- a/document/decorator.md +++ b/document/decorator.md @@ -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` \ No newline at end of file diff --git a/request/test.http b/request/test.http index 519e16d..f52fd5c 100644 --- a/request/test.http +++ b/request/test.http @@ -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 \ No newline at end of file + +### Decorator http test +GET {{host}}/decorator/test/http +Content-Type: application/x-www-form-urlencoded \ No newline at end of file