BaseRequest.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. <?php
  2. namespace App\Module\ThirdParty\Services;
  3. use App\Module\ThirdParty\Dto\Config;
  4. use App\Module\ThirdParty\Dto\Credential;
  5. use App\Module\ThirdParty\Models\ThirdPartyService as ServiceModel;
  6. use App\Module\ThirdParty\Models\ThirdPartyCredential;
  7. use App\Module\ThirdParty\Models\ThirdPartyLog;
  8. use App\Module\ThirdParty\Models\ThirdPartyQuota;
  9. use App\Module\ThirdParty\Enums\SERVICE_STATUS;
  10. use App\Module\ThirdParty\Enums\LOG_LEVEL;
  11. use Illuminate\Support\Facades\Http;
  12. use Illuminate\Support\Facades\Cache;
  13. use Illuminate\Http\Client\Response;
  14. /**
  15. * 第三方请求基类
  16. *
  17. * 抽象化请求概念,不局限于HTTP请求,扩展到调用包的请求方法
  18. * 基类处理配置读取、配额管理、日志记录等通用功能
  19. */
  20. abstract class BaseRequest
  21. {
  22. /**
  23. * 服务代码
  24. */
  25. protected string $serviceCode;
  26. /**
  27. * 服务配置
  28. */
  29. protected ?ServiceModel $service = null;
  30. /**
  31. * 认证凭证
  32. */
  33. protected ?ThirdPartyCredential $credential = null;
  34. /**
  35. * 请求ID
  36. */
  37. protected string $requestId;
  38. /**
  39. * 开始时间
  40. */
  41. protected float $startTime;
  42. /**
  43. * 构造函数
  44. *
  45. * @param string $serviceCode 服务代码
  46. */
  47. public function __construct(string $serviceCode)
  48. {
  49. $this->serviceCode = $serviceCode;
  50. $this->requestId = uniqid('req_', true);
  51. $this->startTime = microtime(true);
  52. // 初始化服务配置
  53. $this->initializeService();
  54. }
  55. /**
  56. * 初始化服务配置
  57. *
  58. * @throws \Exception
  59. */
  60. protected function initializeService(): void
  61. {
  62. $this->service = ServiceModel::where('code', $this->serviceCode)->first();
  63. if (!$this->service) {
  64. throw new \Exception("服务 {$this->serviceCode} 不存在");
  65. }
  66. if (!$this->service->canCallApi()) {
  67. throw new \Exception("服务 {$this->serviceCode} 当前不可用,状态:{$this->service->getStatusLabel()}");
  68. }
  69. // 获取认证凭证
  70. $this->credential = $this->service->getActiveCredential();
  71. if (!$this->credential) {
  72. throw new \Exception("服务 {$this->serviceCode} 没有可用的认证凭证");
  73. }
  74. }
  75. /**
  76. * 执行请求
  77. *
  78. * @param array $params 请求参数
  79. * @return array
  80. * @throws \Exception
  81. */
  82. public function request(array $params = []): array
  83. {
  84. // 检查配额
  85. if (!$this->checkQuota()) {
  86. throw new \Exception("服务 {$this->serviceCode} 配额已用完");
  87. }
  88. try {
  89. // 执行具体的请求逻辑
  90. $result = $this->handler($params);
  91. // 记录成功日志
  92. $this->logRequest($params, $result, true);
  93. // 更新配额
  94. $this->updateQuota();
  95. // 更新凭证使用统计
  96. $this->credential->updateUsageStats();
  97. return $result;
  98. } catch (\Exception $e) {
  99. // 记录失败日志
  100. $this->logRequest($params, [ 'error' => $e->getMessage() ], false);
  101. throw $e;
  102. }
  103. }
  104. /**
  105. * 具体的请求处理逻辑(由子类实现)
  106. *
  107. * @param array $params 请求参数
  108. * @return array
  109. */
  110. abstract protected function handler(array $params = []): array;
  111. abstract protected function getCredential(string $params = ''): Credential;
  112. abstract protected function getConfig(string $params = ''): Config;
  113. /**
  114. * 检查配额
  115. *
  116. * @return bool
  117. */
  118. protected function checkQuota(): bool
  119. {
  120. return QuotaService::checkQuota($this->service);
  121. }
  122. /**
  123. * 更新配额
  124. */
  125. protected function updateQuota(): void
  126. {
  127. QuotaService::updateQuota($this->service);
  128. }
  129. /**
  130. * 记录请求日志
  131. *
  132. * @param array $params 请求参数
  133. * @param array $result 响应结果
  134. * @param bool $success 是否成功
  135. */
  136. protected function logRequest(array $params, array $result, bool $success): void
  137. {
  138. $responseTime = (int)((microtime(true) - $this->startTime) * 1000);
  139. ThirdPartyLog::create([
  140. 'service_id' => $this->service->id,
  141. 'credential_id' => $this->credential->id,
  142. 'request_id' => $this->requestId,
  143. 'method' => 'PACKAGE_CALL',
  144. 'url' => $this->serviceCode,
  145. 'request_headers' => json_encode([]),
  146. 'request_body' => json_encode($params),
  147. 'response_status' => $success ? 200 : 500,
  148. 'response_headers' => json_encode([]),
  149. 'response_body' => json_encode($result),
  150. 'response_time' => $responseTime,
  151. 'success' => $success,
  152. 'error_message' => $success ? null : ($result['error'] ?? '未知错误'),
  153. 'level' => $success ? LOG_LEVEL::INFO->value : LOG_LEVEL::ERROR->value,
  154. 'ip_address' => request()->ip(),
  155. 'user_agent' => request()->userAgent(),
  156. 'called_at' => now(),
  157. ]);
  158. }
  159. /**
  160. * 获取服务配置
  161. *
  162. * @param string|null $key 配置键名,为空则返回全部配置
  163. * @return mixed
  164. */
  165. protected function getConfig(?string $key = null)
  166. {
  167. $config = $this->service->config ?? [];
  168. if ($key === null) {
  169. return $config;
  170. }
  171. return $config[$key] ?? null;
  172. }
  173. /**
  174. * 获取服务信息
  175. *
  176. * @return ServiceModel
  177. */
  178. protected function getService(): ServiceModel
  179. {
  180. return $this->service;
  181. }
  182. /**
  183. * 获取认证凭证
  184. *
  185. * @return ThirdPartyCredential
  186. */
  187. protected function getCredential(): ThirdPartyCredential
  188. {
  189. return $this->credential;
  190. }
  191. /**
  192. * 获取请求ID
  193. *
  194. * @return string
  195. */
  196. protected function getRequestId(): string
  197. {
  198. return $this->requestId;
  199. }
  200. }