laravel中请求失败重试的扩展--Guzzle
背景
开发过程中,跟外部接口对接时,很常见的要考虑到失败重新的情况,这里记录一下我用的失败重试的情况,
重试方法
1、使用 Laravel 的 HTTP 客户端和异常处理
结合异常处理和重试逻辑
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\RequestException;
try {
$response = Http::get('http://example.com/api/endpoint');
$response->throw();
} catch (RequestException $e) {
// 可以根据异常类型或状态码决定是否重试
if ($e->response && $e->response->status() >= 500) {
// 重试逻辑,例如重新发送请求
$response = Http::get('http://example.com/api/endpoint');
}
}
2、Guzzle 及其重试中间件
文档地址:https://docs.guzzlephp.org/en/stable/quickstart.html#creating-a-client
Guzzle 是一个广泛使用的 HTTP 客户端,并且有相应的重试中间件可以实现请求失败的重试。
2.1安装扩展
composer require guzzlehttp/guzzle
2.2失败重试逻辑
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Response;
class YourHttpClientClass {
// 自定义的重试决策函数
public static function retryDecider() {
return function ($retries, $request, $response = null, $exception = null) {
if ($retries >= 3) {
return false;
}
if ($exception instanceof \GuzzleHttp\Exception\ConnectException) {
return true;
}
if ($response) {
// 如果请求有响应,这里根据自己的业务而定,是否继续重试
$res_content = $response->getBody()->getContents();
$res = json_decode($res_content, true);
if (isset($res['error'])) { // 如果不存在status ,更新access_token,再次请求
info('接口请求结果: '. json_encode($res) . '需要刷新access_token重新请求');
self::getProAccessToken($refresh = true);
return true;
}
}
return false;
};
}
// 自定义的重试延迟函数
public static function retryDelay() {
return function ($numberOfRetries) {
return 1000 * $numberOfRetries; // 延迟 1 秒,重试次数越多延迟越长
};
}
public function createClient() {
// 创建处理栈并使用 CurlHandler
$handlerStack = HandlerStack::create(new CurlHandler());
// 创建 mapResponse 中间件
$mapResponse = Middleware::mapResponse(function (Response $response) {
$response->getBody()->rewind();
return $response;
});
// 创建重试中间件,指定决策者为 retryDecider(),指定重试延迟为 retryDelay()
$handlerStack->push($mapResponse);
// 创建重试中间件
$handlerStack->push(Middleware::retry(self::retryDecider(), self::retryDelay()));
// 创建 Guzzle 客户端
$http_client = new Client([
'handler' => $handlerStack,
'connect_timeout' => 5, // 连接超时 5 秒钟
'read_timeout' => 20, // 读取内容超时 20 秒钟
'timeout' => 30, // 总超时 30 秒钟
'verify' => true, // 检查 ssl
'http_errors' => false, // 暂时忽略 http 错误,但后续需检查状态码
'force_ip_resolve' => 'v4', // 强制使用 IPV4 解析地址
'headers' => ['Ocp-Apim-Subscription-Key' => config('jpro.vpcx.api_key') ],
]);
if (strtolower($method) == 'get') {
$options = ['query' => $data ];
$res = $http_client->request('get', $api_url, $options)->getBody()->getContents();
} elseif (strtolower($method) == 'post') {
$res = $http_client->request('post', $api_url, [
'form_params' => $data,
])->getBody()->getContents();
}
return $res;
}
}