WebhookReceiver.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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\ThirdPartyLog;
  7. use App\Module\ThirdParty\Enums\LOG_LEVEL;
  8. use Illuminate\Http\Request;
  9. use Illuminate\Http\JsonResponse;
  10. use Illuminate\Support\Facades\Log;
  11. /**
  12. * Webhook接收器基类
  13. *
  14. * 专门用于接收第三方Webhook通知
  15. * 与BaseWebhook不同,这个类专注于接收而不是发送
  16. */
  17. abstract class WebhookReceiver
  18. {
  19. /**
  20. * 服务代码
  21. */
  22. protected string $serviceCode;
  23. /**
  24. * 服务配置
  25. */
  26. protected ?ServiceModel $service = null;
  27. /**
  28. * 请求对象
  29. */
  30. protected Request $request;
  31. /**
  32. * 请求ID
  33. */
  34. protected string $requestId;
  35. /**
  36. * 开始时间
  37. */
  38. protected float $startTime;
  39. /**
  40. * 构造函数
  41. *
  42. * @param string $serviceCode 服务代码
  43. * @param Request $request 请求对象
  44. * @param ServiceModel $service 服务配置对象
  45. */
  46. public function __construct(string $serviceCode, Request $request, ServiceModel $service)
  47. {
  48. $this->serviceCode = $serviceCode;
  49. $this->request = $request;
  50. $this->service = $service;
  51. $this->requestId = uniqid('webhook_', true);
  52. $this->startTime = microtime(true);
  53. }
  54. /**
  55. * 处理Webhook请求
  56. *
  57. * @param string $action 操作类型
  58. * @return JsonResponse
  59. */
  60. public function handle(string $action): JsonResponse
  61. {
  62. try {
  63. // 验证请求格式
  64. $this->validateRequest();
  65. // 执行具体的处理逻辑
  66. $result = $this->handler($action, $this->request);
  67. // 记录成功日志
  68. $this->logWebhook($action, $this->request->all(), $result, true);
  69. return response()->json([
  70. 'success' => true,
  71. 'data' => $result
  72. ]);
  73. } catch (\Exception $e) {
  74. // 记录失败日志
  75. $this->logWebhook($action, $this->request->all(), ['error' => $e->getMessage()], false);
  76. Log::error("Webhook处理失败: {$this->serviceCode}/{$action}", [
  77. 'error' => $e->getMessage(),
  78. 'request_id' => $this->requestId,
  79. 'request_data' => $this->request->all(),
  80. ]);
  81. return response()->json([
  82. 'success' => false,
  83. 'error' => $e->getMessage(),
  84. 'request_id' => $this->requestId,
  85. ], 400);
  86. }
  87. }
  88. /**
  89. * 具体的Webhook处理逻辑(由子类实现)
  90. *
  91. * @param string $action 操作类型
  92. * @param Request $request 请求对象
  93. * @return array
  94. */
  95. abstract protected function handler(string $action, Request $request): array;
  96. /**
  97. *
  98. * @return Config
  99. */
  100. abstract protected function getConfigDto():Config;
  101. /**
  102. * 验证请求格式(由子类重写)
  103. *
  104. * @throws \Exception
  105. */
  106. protected function validateRequest(): void
  107. {
  108. // 默认不做验证,子类可以重写此方法
  109. }
  110. /**
  111. * 记录Webhook日志
  112. *
  113. * @param string $action 操作类型
  114. * @param array $requestData 请求数据
  115. * @param array $result 处理结果
  116. * @param bool $success 是否成功
  117. */
  118. protected function logWebhook(string $action, array $requestData, array $result, bool $success): void
  119. {
  120. $responseTime = (int)((microtime(true) - $this->startTime) * 1000);
  121. // 在响应体中包含action信息
  122. $logResult = array_merge($result, ['webhook_action' => $action]);
  123. ThirdPartyLog::create([
  124. 'service_id' => $this->service->id,
  125. 'credential_id' => null, // Webhook接收器不需要凭证
  126. 'request_id' => $this->requestId,
  127. 'method' => 'WEBHOOK',
  128. 'url' => $this->request->fullUrl(),
  129. 'request_headers' => json_encode($this->request->headers->all()),
  130. 'request_body' => json_encode($requestData),
  131. 'response_status' => $success ? 200 : 400,
  132. 'response_headers' => json_encode([]),
  133. 'response_body' => json_encode($logResult),
  134. 'response_time' => $responseTime,
  135. 'success' => $success,
  136. 'error_message' => $success ? null : ($result['error'] ?? '未知错误'),
  137. 'level' => $success ? LOG_LEVEL::INFO->value : LOG_LEVEL::ERROR->value,
  138. 'ip_address' => $this->request->ip(),
  139. 'user_agent' => $this->request->userAgent(),
  140. 'called_at' => now(),
  141. ]);
  142. }
  143. /**
  144. * 获取服务配置
  145. *
  146. * @param string|null $key 配置键名,为空则返回全部配置
  147. * @return mixed
  148. */
  149. protected function getConfig(?string $key = null)
  150. {
  151. $config = $this->service->config ?? [];
  152. if ($key === null) {
  153. return $config;
  154. }
  155. return $config[$key] ?? null;
  156. }
  157. /**
  158. * 获取服务信息
  159. *
  160. * @return ServiceModel
  161. */
  162. protected function getService(): ServiceModel
  163. {
  164. return $this->service;
  165. }
  166. /**
  167. * 获取请求ID
  168. *
  169. * @return string
  170. */
  171. protected function getRequestId(): string
  172. {
  173. return $this->requestId;
  174. }
  175. /**
  176. * 获取请求对象
  177. *
  178. * @return Request
  179. */
  180. protected function getRequest(): Request
  181. {
  182. return $this->request;
  183. }
  184. }