| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- <?php
- /*
- * This file is part of the overtrue/wechat.
- *
- * (c) overtrue <i@overtrue.me>
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
- namespace EasyWeChat\Kernel;
- use EasyWeChat\Kernel\Contracts\AccessTokenInterface;
- use EasyWeChat\Kernel\Http\Response;
- use EasyWeChat\Kernel\Traits\HasHttpRequests;
- use GuzzleHttp\MessageFormatter;
- use GuzzleHttp\Middleware;
- use Psr\Http\Message\RequestInterface;
- use Psr\Http\Message\ResponseInterface;
- use Psr\Log\LogLevel;
- /**
- * Class BaseClient.
- *
- * @author overtrue <i@overtrue.me>
- */
- class BaseClient
- {
- use HasHttpRequests { request as performRequest; }
- /**
- * @var \EasyWeChat\Kernel\ServiceContainer
- */
- protected $app;
- /**
- * @var \EasyWeChat\Kernel\Contracts\AccessTokenInterface
- */
- protected $accessToken;
- /**
- * @var string
- */
- protected $baseUri;
- /**
- * BaseClient constructor.
- *
- * @param \EasyWeChat\Kernel\ServiceContainer $app
- */
- public function __construct(ServiceContainer $app, AccessTokenInterface $accessToken = null)
- {
- $this->app = $app;
- $this->accessToken = $accessToken ?? $this->app['access_token'];
- }
- /**
- * GET request.
- *
- * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
- *
- * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
- * @throws \GuzzleHttp\Exception\GuzzleException
- */
- public function httpGet(string $url, array $query = [])
- {
- return $this->request($url, 'GET', ['query' => $query]);
- }
- /**
- * POST request.
- *
- * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
- *
- * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
- * @throws \GuzzleHttp\Exception\GuzzleException
- */
- public function httpPost(string $url, array $data = [])
- {
- return $this->request($url, 'POST', ['form_params' => $data]);
- }
- /**
- * JSON request.
- *
- * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
- *
- * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
- * @throws \GuzzleHttp\Exception\GuzzleException
- */
- public function httpPostJson(string $url, array $data = [], array $query = [])
- {
- return $this->request($url, 'POST', ['query' => $query, 'json' => $data]);
- }
- /**
- * Upload file.
- *
- * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
- *
- * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
- * @throws \GuzzleHttp\Exception\GuzzleException
- */
- public function httpUpload(string $url, array $files = [], array $form = [], array $query = [])
- {
- $multipart = [];
- foreach ($files as $name => $path) {
- $multipart[] = [
- 'name' => $name,
- 'contents' => fopen($path, 'r'),
- ];
- }
- foreach ($form as $name => $contents) {
- $multipart[] = compact('name', 'contents');
- }
- return $this->request($url, 'POST', ['query' => $query, 'multipart' => $multipart, 'connect_timeout' => 30, 'timeout' => 30, 'read_timeout' => 30]);
- }
- public function getAccessToken(): AccessTokenInterface
- {
- return $this->accessToken;
- }
- /**
- * @return $this
- */
- public function setAccessToken(AccessTokenInterface $accessToken)
- {
- $this->accessToken = $accessToken;
- return $this;
- }
- /**
- * @param bool $returnRaw
- *
- * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
- *
- * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
- * @throws \GuzzleHttp\Exception\GuzzleException
- */
- public function request(string $url, string $method = 'GET', array $options = [], $returnRaw = false)
- {
- if (empty($this->middlewares)) {
- $this->registerHttpMiddlewares();
- }
- $response = $this->performRequest($url, $method, $options);
- $this->app->events->dispatch(new Events\HttpResponseCreated($response));
- return $returnRaw ? $response : $this->castResponseToType($response, $this->app->config->get('response_type'));
- }
- /**
- * @return \EasyWeChat\Kernel\Http\Response
- *
- * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
- * @throws \GuzzleHttp\Exception\GuzzleException
- */
- public function requestRaw(string $url, string $method = 'GET', array $options = [])
- {
- return Response::buildFromPsrResponse($this->request($url, $method, $options, true));
- }
- /**
- * Register Guzzle middlewares.
- */
- protected function registerHttpMiddlewares()
- {
- // retry
- $this->pushMiddleware($this->retryMiddleware(), 'retry');
- // access token
- $this->pushMiddleware($this->accessTokenMiddleware(), 'access_token');
- // log
- $this->pushMiddleware($this->logMiddleware(), 'log');
- }
- /**
- * Attache access token to request query.
- *
- * @return \Closure
- */
- protected function accessTokenMiddleware()
- {
- return function (callable $handler) {
- return function (RequestInterface $request, array $options) use ($handler) {
- if ($this->accessToken) {
- $request = $this->accessToken->applyToRequest($request, $options);
- }
- return $handler($request, $options);
- };
- };
- }
- /**
- * Log the request.
- *
- * @return \Closure
- */
- protected function logMiddleware()
- {
- $formatter = new MessageFormatter($this->app['config']['http.log_template'] ?? MessageFormatter::DEBUG);
- return Middleware::log($this->app['logger'], $formatter, LogLevel::DEBUG);
- }
- /**
- * Return retry middleware.
- *
- * @return \Closure
- */
- protected function retryMiddleware()
- {
- return Middleware::retry(function (
- $retries,
- RequestInterface $request,
- ResponseInterface $response = null
- ) {
- // Limit the number of retries to 2
- if ($retries < $this->app->config->get('http.max_retries', 1) && $response && $body = $response->getBody()) {
- // Retry on server errors
- $response = json_decode($body, true);
- if (!empty($response['errcode']) && in_array(abs($response['errcode']), [40001, 40014, 42001], true)) {
- $this->accessToken->refresh();
- $this->app['logger']->debug('Retrying with refreshed access token.');
- return true;
- }
- }
- return false;
- }, function () {
- return abs($this->app->config->get('http.retry_delay', 500));
- });
- }
- }
|