| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- <?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.
- */
- /**
- * AbstractAPI.php.
- *
- * This file is part of the wechat-components.
- *
- * (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\Core;
- use EasyWeChat\Core\Exceptions\HttpException;
- use EasyWeChat\Support\Collection;
- use EasyWeChat\Support\Log;
- use GuzzleHttp\Middleware;
- use GuzzleHttp\Psr7\Uri;
- use Psr\Http\Message\RequestInterface;
- use Psr\Http\Message\ResponseInterface;
- /**
- * Class AbstractAPI.
- */
- abstract class AbstractAPI
- {
- /**
- * Http instance.
- *
- * @var \EasyWeChat\Core\Http
- */
- protected $http;
- /**
- * The request token.
- *
- * @var \EasyWeChat\Core\AccessToken
- */
- protected $accessToken;
- const GET = 'get';
- const POST = 'post';
- const JSON = 'json';
- /**
- * @var int
- */
- protected static $maxRetries = 2;
- /**
- * Constructor.
- *
- * @param \EasyWeChat\Core\AccessToken $accessToken
- */
- public function __construct(AccessToken $accessToken)
- {
- $this->setAccessToken($accessToken);
- }
- /**
- * Return the http instance.
- *
- * @return \EasyWeChat\Core\Http
- */
- public function getHttp()
- {
- if (is_null($this->http)) {
- $this->http = new Http();
- }
- if (0 === count($this->http->getMiddlewares())) {
- $this->registerHttpMiddlewares();
- }
- return $this->http;
- }
- /**
- * Set the http instance.
- *
- * @param \EasyWeChat\Core\Http $http
- *
- * @return $this
- */
- public function setHttp(Http $http)
- {
- $this->http = $http;
- return $this;
- }
- /**
- * Return the current accessToken.
- *
- * @return \EasyWeChat\Core\AccessToken
- */
- public function getAccessToken()
- {
- return $this->accessToken;
- }
- /**
- * Set the request token.
- *
- * @param \EasyWeChat\Core\AccessToken $accessToken
- *
- * @return $this
- */
- public function setAccessToken(AccessToken $accessToken)
- {
- $this->accessToken = $accessToken;
- return $this;
- }
- /**
- * @param int $retries
- */
- public static function maxRetries($retries)
- {
- self::$maxRetries = abs($retries);
- }
- /**
- * Parse JSON from response and check error.
- *
- * @param string $method
- * @param array $args
- *
- * @return \EasyWeChat\Support\Collection | null
- *
- * @throws \EasyWeChat\Core\Exceptions\HttpException
- */
- public function parseJSON($method, array $args)
- {
- $http = $this->getHttp();
- $contents = $http->parseJSON(call_user_func_array([$http, $method], $args));
- if (empty($contents)) {
- return null;
- }
- $this->checkAndThrow($contents);
- return new Collection($contents);
- }
- /**
- * Register Guzzle middlewares.
- */
- protected function registerHttpMiddlewares()
- {
- // log
- $this->http->addMiddleware($this->logMiddleware());
- // retry
- $this->http->addMiddleware($this->retryMiddleware());
- // access token
- $this->http->addMiddleware($this->accessTokenMiddleware());
- }
- /**
- * 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) {
- return $handler($request, $options);
- }
- $field = $this->accessToken->getQueryName();
- $token = $this->accessToken->getToken();
- $request = $request->withUri(Uri::withQueryValue($request->getUri(), $field, $token));
- return $handler($request, $options);
- };
- };
- }
- /**
- * Log the request.
- *
- * @return \Closure
- */
- protected function logMiddleware()
- {
- return Middleware::tap(function (RequestInterface $request, $options) {
- Log::debug("Request: {$request->getMethod()} {$request->getUri()} ".json_encode($options));
- Log::debug('Request headers:'.json_encode($request->getHeaders()));
- });
- }
- /**
- * 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 <= self::$maxRetries && $response && $body = $response->getBody()) {
- // Retry on server errors
- if (false !== stripos($body, 'errcode') && (false !== stripos($body, '40001') || false !== stripos($body, '42001'))) {
- $field = $this->accessToken->getQueryName();
- $token = $this->accessToken->getToken(true);
- $request = $request->withUri($newUri = Uri::withQueryValue($request->getUri(), $field, $token));
- Log::debug("Retry with Request Token: {$token}");
- Log::debug("Retry with Request Uri: {$newUri}");
- return true;
- }
- }
- return false;
- });
- }
- /**
- * Check the array data errors, and Throw exception when the contents contains error.
- *
- * @param array $contents
- *
- * @throws \EasyWeChat\Core\Exceptions\HttpException
- */
- protected function checkAndThrow(array $contents)
- {
- if (isset($contents['errcode']) && 0 !== $contents['errcode']) {
- if (empty($contents['errmsg'])) {
- $contents['errmsg'] = 'Unknown';
- }
- throw new HttpException($contents['errmsg'], $contents['errcode']);
- }
- }
- }
|