背景
開發過程中,跟外部接口對接時,很常見的要考慮到失敗重新的情況,這里記錄一下我用的失敗重試的情況,
重試方法
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;}
}