1. 程式人生 > 其它 >php阿里雲oss-sdk上傳失敗情況處理

php阿里雲oss-sdk上傳失敗情況處理

現象

oss上傳沒有成功,但是拿到了地址,導致訪問時返回404狀態碼

思路

我們先看自己寫的上傳oss部分程式碼

public function oss(string $file, string $object)
{
    $ossClient = new OssClient($this->config['accessKeyId'], $this->config['accessKeySecret'], $this->config['endpoint']);
    $result    = $ossClient->uploadFile($this->config['bucket'], ltrim($object, '/'), $file);
    return $result['oss-request-url'];
}

按理說是由sdk返回的result中拿到的地址,上傳失敗應該會直接丟擲異常
再看其中uploadFile程式碼部分

public function uploadFile($bucket, $object, $file, $options = NULL)
{
    // ...省略程式碼
    $response = $this->auth($options);
    $result = new PutSetDeleteResult($response);
    return $result->getData();
}

其中主要方法是$this->auth($options)

,再進去看

private function auth($options)
{
    // ...省略程式碼

    try {
        $request->send_request();
    } catch (RequestCore_Exception $e) {
        throw(new OssException('RequestCoreException: ' . $e->getMessage()));
    }
    $response_header = $request->get_response_header();
    $response_header['oss-request-url'] = $requestUrl;
    $response_header['oss-redirects'] = $this->redirects;
    $response_header['oss-stringtosign'] = $string_to_sign;
    $response_header['oss-requestheaders'] = $request->request_headers;

    $data = new ResponseCore($response_header, $request->get_response_body(), $request->get_response_code());
    //retry if OSS Internal Error
    if ((integer)$request->get_response_code() === 500) {
        if ($this->redirects <= $this->maxRetries) {
            //Sets the sleep time betwen each retry.
            $delay = (integer)(pow(4, $this->redirects) * 100000);
            usleep($delay);
            $this->redirects++;
            $data = $this->auth($options);
        }
    }
    
    $this->redirects = 0;
    return $data;
}

可以看到拋異常情況只在send_request方法,而裡面只在curl本身無法請求(比如host無法解析)才會丟擲RequestCore_Exception異常
也就是說如果是業務類的錯誤是會正常走下去的
雖然response_code為500時會有重試,但是在這之前已經建立了response物件
如果非500錯誤,或者超過重試次數都會返回這個物件,最終情況就是不管怎麼樣都會返回result結構體

解決

在拿到result結構體後先進行response_code判斷,程式碼如下

public function oss(string $file, string $object)
{
    $ossClient = new OssClient($this->config['accessKeyId'], $this->config['accessKeySecret'], $this->config['endpoint']);
    $result    = $ossClient->uploadFile($this->config['bucket'], ltrim($object, '/'), $file);
    if ($result['info']['http_code'] !== 200) {
        throw new OssException('上傳失敗');
    }
    return $result['oss-request-url'];
}

補充

查閱了官方示例也沒有對這些情況進行處理,示例如下:
地址:https://help.aliyun.com/document_detail/88473.html

// ...省略程式碼
try{
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);

    $ossClient->uploadFile($bucket, $object, $filePath);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . "OK" . "\n");

附上文件中其他錯誤碼說明,文件連結:https://help.aliyun.com/document_detail/31978.html#section-orz-dlw-bz

錯誤碼 HTTP狀態碼 描述
MissingContentLength 411 請求頭沒有采用chunked encoding編碼方式,或沒有設定Content-Length引數。
InvalidEncryptionAlgorithmError 400 指定x-oss-server-side-encryption的值無效。取值:AES256、KMS或SM4。
AccessDenied 403 新增Object時,使用者對設定的Bucket沒有訪問許可權。
NoSuchBucket 404 新增Object時,設定的Bucket不存在。
InvalidObjectName 400 傳入的Object key長度大於1023位元組。
InvalidArgument 400 返回該錯誤的可能原因如下:新增的Object大小超過5 GB。x-oss-storage-class等引數的值無效。
RequestTimeout 400 指定了Content-Length,但沒有傳送訊息體,或者傳送的訊息體小於指定的大小。此種情況下伺服器會一直等待,直至請求超時。
Bad Request 400 在請求中指定Content-MD5後,OSS會計算所傳送資料的MD5值,並與請求中Conent-MD5的值進行比較。如果二者不一致,則返回該錯誤。
KmsServiceNotEnabled 403 x-oss-server-side-encryption指定為KMS,但沒有預先購買KMS套件。
FileAlreadyExists 409 當請求的Header中攜帶x-oss-forbid-overwrite=true時,表示禁止覆蓋同名檔案。如果同名檔案已存在,則返回該錯誤。
FileImmutable 409 Bucket中的資料處於被保護狀態時,如果嘗試刪除或修改相應資料,則返回該錯誤。