HasHttpRequests.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <?php
  2. /*
  3. * This file is part of the overtrue/wechat.
  4. *
  5. * (c) overtrue <i@overtrue.me>
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. namespace EasyWeChat\Kernel\Traits;
  11. use GuzzleHttp\Client;
  12. use GuzzleHttp\ClientInterface;
  13. use GuzzleHttp\HandlerStack;
  14. use Psr\Http\Message\ResponseInterface;
  15. /**
  16. * Trait HasHttpRequests.
  17. *
  18. * @author overtrue <i@overtrue.me>
  19. */
  20. trait HasHttpRequests
  21. {
  22. use ResponseCastable;
  23. /**
  24. * @var \GuzzleHttp\ClientInterface
  25. */
  26. protected $httpClient;
  27. /**
  28. * @var array
  29. */
  30. protected $middlewares = [];
  31. /**
  32. * @var \GuzzleHttp\HandlerStack
  33. */
  34. protected $handlerStack;
  35. /**
  36. * @var array
  37. */
  38. protected static $defaults = [
  39. 'curl' => [
  40. CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
  41. ],
  42. ];
  43. /**
  44. * Set guzzle default settings.
  45. *
  46. * @param array $defaults
  47. */
  48. public static function setDefaultOptions($defaults = [])
  49. {
  50. self::$defaults = $defaults;
  51. }
  52. /**
  53. * Return current guzzle default settings.
  54. *
  55. * @return array
  56. */
  57. public static function getDefaultOptions(): array
  58. {
  59. return self::$defaults;
  60. }
  61. /**
  62. * Set GuzzleHttp\Client.
  63. *
  64. * @param \GuzzleHttp\ClientInterface $httpClient
  65. *
  66. * @return $this
  67. */
  68. public function setHttpClient(ClientInterface $httpClient)
  69. {
  70. $this->httpClient = $httpClient;
  71. return $this;
  72. }
  73. /**
  74. * Return GuzzleHttp\ClientInterface instance.
  75. *
  76. * @return ClientInterface
  77. */
  78. public function getHttpClient(): ClientInterface
  79. {
  80. if (!($this->httpClient instanceof ClientInterface)) {
  81. if (property_exists($this, 'app') && $this->app['http_client']) {
  82. $this->httpClient = $this->app['http_client'];
  83. } else {
  84. $this->httpClient = new Client(['handler' => HandlerStack::create($this->getGuzzleHandler())]);
  85. }
  86. }
  87. return $this->httpClient;
  88. }
  89. /**
  90. * Add a middleware.
  91. *
  92. * @param callable $middleware
  93. * @param string $name
  94. *
  95. * @return $this
  96. */
  97. public function pushMiddleware(callable $middleware, string $name = null)
  98. {
  99. if (!is_null($name)) {
  100. $this->middlewares[$name] = $middleware;
  101. } else {
  102. array_push($this->middlewares, $middleware);
  103. }
  104. return $this;
  105. }
  106. /**
  107. * Return all middlewares.
  108. *
  109. * @return array
  110. */
  111. public function getMiddlewares(): array
  112. {
  113. return $this->middlewares;
  114. }
  115. /**
  116. * Make a request.
  117. *
  118. * @param string $url
  119. * @param string $method
  120. * @param array $options
  121. *
  122. * @return \Psr\Http\Message\ResponseInterface
  123. *
  124. * @throws \GuzzleHttp\Exception\GuzzleException
  125. */
  126. public function request($url, $method = 'GET', $options = []): ResponseInterface
  127. {
  128. $method = strtoupper($method);
  129. $options = array_merge(self::$defaults, $options, ['handler' => $this->getHandlerStack()]);
  130. $options = $this->fixJsonIssue($options);
  131. if (property_exists($this, 'baseUri') && !is_null($this->baseUri)) {
  132. $options['base_uri'] = $this->baseUri;
  133. }
  134. $response = $this->getHttpClient()->request($method, $url, $options);
  135. $response->getBody()->rewind();
  136. return $response;
  137. }
  138. /**
  139. * @param \GuzzleHttp\HandlerStack $handlerStack
  140. *
  141. * @return $this
  142. */
  143. public function setHandlerStack(HandlerStack $handlerStack)
  144. {
  145. $this->handlerStack = $handlerStack;
  146. return $this;
  147. }
  148. /**
  149. * Build a handler stack.
  150. *
  151. * @return \GuzzleHttp\HandlerStack
  152. */
  153. public function getHandlerStack(): HandlerStack
  154. {
  155. if ($this->handlerStack) {
  156. return $this->handlerStack;
  157. }
  158. $this->handlerStack = HandlerStack::create($this->getGuzzleHandler());
  159. foreach ($this->middlewares as $name => $middleware) {
  160. $this->handlerStack->push($middleware, $name);
  161. }
  162. return $this->handlerStack;
  163. }
  164. /**
  165. * @param array $options
  166. *
  167. * @return array
  168. */
  169. protected function fixJsonIssue(array $options): array
  170. {
  171. if (isset($options['json']) && is_array($options['json'])) {
  172. $options['headers'] = array_merge($options['headers'] ?? [], ['Content-Type' => 'application/json']);
  173. if (empty($options['json'])) {
  174. $options['body'] = \GuzzleHttp\json_encode($options['json'], JSON_FORCE_OBJECT);
  175. } else {
  176. $options['body'] = \GuzzleHttp\json_encode($options['json'], JSON_UNESCAPED_UNICODE);
  177. }
  178. unset($options['json']);
  179. }
  180. return $options;
  181. }
  182. /**
  183. * Get guzzle handler.
  184. *
  185. * @return callable
  186. */
  187. protected function getGuzzleHandler()
  188. {
  189. if (property_exists($this, 'app') && isset($this->app['guzzle_handler'])) {
  190. return is_string($handler = $this->app->raw('guzzle_handler'))
  191. ? new $handler()
  192. : $handler;
  193. }
  194. return \GuzzleHttp\choose_handler();
  195. }
  196. }