記錄使用 guzzlehttp 異常捕獲踩坑記錄

barret發表於2020-04-28

記錄一下自己專案中的坑, 如有不對之處希望大家指正。

在之前公司專案工作中,經常對接海外的支付,常常用到guzzlehttp 用作介面請求的依賴包,由於沒有查閱文件和程式碼,捕獲異常處理的不正確, 導致重複支付的現象。

try {
    $result = $client->request('post', $url, $options);
} catch (\Throwable $throwable) {
    //donging something
    return false;
}

最開始的時候簡單的這樣捕獲異常,以為這樣的異常都是請求失敗,但是後面由於重複支付的問題,檢視了guzzlehttp的程式碼,發現他們設定了處理請求的中介軟體,程式碼如下:

public static function httpErrors()
 {
     return function (callable $handler) {
         return function ($request, array $options) use ($handler) {
             if (empty($options['http_errors'])) {
                 return $handler($request, $options);
            }
            return $handler($request, $options)->then(
                function (ResponseInterface $response) use ($request, $handler) {
                    $code = $response->getStatusCode();
                    if ($code < 400) {
                    return $response;
                }
                throw RequestException::create($request, $response);
            });
         };
     };
 }

由於上面的可以看出,guzzlehttp 根據請求的httpcode 做了不同的響應,只正常返回<=400以下的響應,其餘的都丟擲的異常,主要是倆類異常4XX 和5XX的異常類,程式碼如下:

$level = (int) floor($response->getStatusCode() / 100);
if ($level === 4) {
    $label = 'Client error';
    $className = ClientException::class;
} elseif ($level === 5) {
    $label = 'Server error';
    $className = ServerException::class;
} else {
    $label = 'Unsuccessful request';
    $className = __CLASS__;
}

所以最後我在請求異常處理裡面根據不同的異常類分別處理, 這樣就可以分別判斷請求狀態,哪些可以重試,哪些支付不能重試。避免了類似5XX 的服務端的錯誤,在專案中進行了支付重試,修改後程式碼如下:

try {
    $result = $client->request('post', $url, $options);
} catch (\Throwable $throwable) {
    if ($throwable instanceof ClientException) {
        //doing something 
        return ...
    }
    if ($throwable instanceof ServerException) {
        //doing something 
        return ...
    }
    //doing something
    return false;
}

以上是我記錄guzzlehttp 的異常捕獲遇到的坑,如有錯誤請大家指正

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章