BaseRequest.php 5.7 KB

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