push(Middleware::retry(self::retryPolicy(), self::retryDelay())); $config = [ 'headers' => [ 'Accept' => 'application/json; charset=utf-8', 'Content-Type' => 'application/json; charset=utf-8', 'Hash' => self::getHash() ], 'base_uri' => self::getHost(), 'connect_timeout' => 10, 'timeout' => 60, 'handler' => $stack, 'debug' => true ]; return new Client($config); } /** * 重试策略 * * @return callable */ public static function retryPolicy(): callable { return function (int $retries, RequestInterface $request, ResponseInterface $response = null, \Throwable $exception = null): bool { // 记录异常信息 if ($exception) { dump($exception->getMessage()); Log::error("重试异常: " . $exception->getMessage()); } // 检查是否为连接异常或请求异常(包括超时) $should_retry = false; if ($exception) { // 处理连接异常(包括连接超时) if ($exception instanceof ConnectException) { $should_retry = true; } // 处理请求异常(包括请求超时) elseif ($exception instanceof RequestException) { // 如果是超时导致的请求异常 if (strpos($exception->getMessage(), 'timed out') !== false) { $should_retry = true; } // 如果有响应,检查状态码 elseif ($exception->hasResponse()) { $status_code = $exception->getResponse()->getStatusCode(); $should_retry = in_array($status_code, [429, 500, 502, 503, 504]); } } } // 首先检查重试次数 if ($retries >= self::MAX_RETRIES) { return false; } // 检查状态码 (需要先确保 $response 不为 null) $status_code_error = $response && in_array($response->getStatusCode(), [429, 500, 502, 503, 504]); // 如果是应该重试的异常、状态码错误或响应为 null,则重试 return $should_retry || $status_code_error || is_null($response); }; } /** * 重试延迟策略 * * @return callable */ public static function retryDelay(): callable { return function (int $retries, ResponseInterface $response = null): int { $delay = 0; if (is_null($response) || !$response->hasHeader('Retry-After')) { $delay = RetryMiddleware::exponentialDelay($retries) * 5; } else { $retryAfter = $response->getHeaderLine('Retry-After'); $delay = $retryAfter; if (!is_numeric($retryAfter)) { $delay = (new \DateTime($retryAfter))->getTimestamp() - time(); } $delay = (int)$delay * 1000; } $seconds = $delay / 1000; $message = "请求失败, 此为第 $retries 次尝试,{$seconds} 秒之后重试"; // 如果有响应,添加状态码信息 if ($response) { $code = $response->getStatusCode(); dump($response->getBody()->getContents()); $message = "请求失败, 远程服务器响应码为 $code, 此为第 $retries 次尝试,{$seconds} 秒之后重试"; } dump($message); Log::error($message); return $delay; }; } static function get(string $path, array $query = []): array { try{ $response = static::create()->request('GET', $path, ['query' => $query]); // dump($response); return static::parse($response); }catch(\Throwable $exception) { dump($exception->getMessage()); dump($exception->getTraceAsString()); exit(1); } } static function post(string $path, array $query = [], array $data = []): array { try{ $response = static::create()->request('POST', $path, ['query' => $query, 'body' => json_encode($data)]); // dump($response); // dump(static::parse($response)); return static::parse($response); }catch(\Throwable $exception){ dump($exception->getMessage()); dump($exception->getTraceAsString()); exit(1); } } static function put(string $path, array $query = [], array $data = []) { try{ $response = static::create()->request('PUT', $path, ['query' => $query, 'body' => json_encode($data)]); // dump($response); return static::parse($response); }catch(\Throwable $exception){ dump($exception->getMessage()); dump($exception->getTraceAsString()); exit(1); } } static function delete(string $path) { try{ $response = static::create()->request('DELETE', $path); // dump($response); return static::parse($response); }catch(\Throwable $exception){ dump($exception->getMessage()); dump($exception->getTraceAsString()); exit(1); } } protected static function parse(ResponseInterface $response): array { $http_code = $response->getStatusCode(); $body = $response->getBody(); // dump($body->getContents()); // when deal with stream object, need to move to pointer to the ram head $body->rewind(); $content = $body->getContents(); $payload = \json_decode($content, 1); if ($http_code == 200) { return $payload; } } }