编辑代码

<?php 
//JSRUN引擎2.0,支持多达30种语言在线运行,全仿真在线交互输入输出。 
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Request as Psr7Request;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use think\facade\Cache;

class HahaService
{
    protected $client;

    public function __construct()
    {
        $this->client = $this->createClientWithRetry();
    }

    protected function createClientWithRetry()
    {
        $handlerStack = HandlerStack::create();
        
        $handlerStack->push(Middleware::retry(
            function ($retry, RequestInterface $request, ResponseInterface $response = null, $exception = null) {
                // 最大重试次数
                if ($retry >= 3) {
                    return false;
                }

                // 检查是否是 401 未授权错误
                if ($response && $response->getStatusCode() == 401) {
                    // 刷新 Token
                    $newToken = $this->refreshToken();
                    
                    // 更新请求的 Authorization 头
                    $request = $request->withHeader('Authorization', 'Bearer ' . $newToken);
                    
                    return true;
                }

                // 对于网络错误也可以重试
                if ($exception instanceof \GuzzleHttp\Exception\ConnectException) {
                    return true;
                }

                return false;
            },
            function ($retry) {
                // 指数退避策略
                return 1000 * pow(2, $retry); // 1s, 2s, 4s
            }
        ));

        return new Client([
            'handler' => $handlerStack,
            'timeout' => 10.0, // 设置超时时间
        ]);
    }

    protected function refreshToken()
    {
        try {
            // 实现 Token 刷新逻辑
            $tokenResponse = $this->originalRequest('POST', '/token', [
                'form_params' => [
                    'grant_type' => 'client_credentials',
                    // 其他必要的认证参数
                ]
            ]);

            $newToken = $tokenResponse['access_token'];
            
            // 缓存新 Token
            Cache::set('haha_access_token', $newToken, 7200);

            return $newToken;
        } catch (\Exception $e) {
            // 处理 Token 刷新失败的情况
            throw new \RuntimeException('Failed to refresh token: ' . $e->getMessage());
        }
    }

    // 原始请求方法,用于 Token 刷新时绕过重试机制
    protected function originalRequest($method, $uri, $options = [])
    {
        // 使用原始 Guzzle 客户端发起请求
        $defaultClient = new Client();
        $response = $defaultClient->request($method, $this->baseUrl . $uri, $options);
        
        return json_decode($response->getBody()->getContents(), true);
    }

    public function request($method, $uri, $options = [])
    {
        // 获取缓存的 Token
        $token = Cache::get('haha_access_token');

        // 如果 Token 不存在,先获取
        if (!$token) {
            $token = $this->refreshToken();
        }

        // 设置 Authorization 头
        $options['headers']['Authorization'] = 'Bearer ' . $token;

        // 发起请求
        return $this->client->request($method, $uri, $options);
    }
}