阿里云文件存儲OSS的后端與移動(dòng)端集成

【寫在前面】
建議初次接觸OSS的童鞋可以根據(jù)本文自行操作一遍,能先實(shí)現(xiàn)功能,有時(shí)間的話再看阿里云OSS的文檔,進(jìn)行局部優(yōu)化。那是一份什么樣的文檔的呢?就是你翻來覆去的看,然后你越看就越想把寫文檔的人拉過來揍一頓的感覺,總之誰看誰知道。

閱讀本文時(shí),需要注意本文中代碼的注釋內(nèi)容;圖片模糊問題不大,可以查看原圖,而且只要能找準(zhǔn)地方就行,我都打紅框了。

【正文】
后端環(huán)境:ubuntu系統(tǒng) + python
移動(dòng)端: android

本文采用后端授權(quán)stsToken給移動(dòng)端的方式,實(shí)現(xiàn)移動(dòng)端文件直傳OSS。

【整體流程描述】
移動(dòng)端向后端發(fā)送獲取stsToken的請求,后端接收到該請求后,于后端環(huán)境中執(zhí)行請求OSS授權(quán)的stsToken的請求,然后將獲取的stsToken返回給移動(dòng)端,移動(dòng)端獲取stsToken后用以實(shí)例化OSSCredentialProvider,進(jìn)而實(shí)例化OSS,通過OSS的實(shí)例化對象實(shí)現(xiàn)上傳。

【整體流程圖示】


移動(dòng)端文件直傳流程圖

【實(shí)現(xiàn)過程】

一、在OSS控制臺中:

1、首先創(chuàng)建Bucket空間:
進(jìn)入OSS控制臺中找到新建Bucket,然后點(diǎn)它。就行了

2、開通sts服務(wù),如下圖,進(jìn)入你的OSS控制臺,點(diǎn)擊紅框中前往RAM控制臺


image.png

如下圖,點(diǎn)擊開始授權(quán):


image.png

如果你之前沒有創(chuàng)建過RAM賬號,則此次創(chuàng)建之后會生成AccessKeyId、AccessKeySecret這兩個(gè)密鑰和RoleArn這個(gè)角色信息,此次請務(wù)必進(jìn)行保管。如下圖會先顯示前二者:
image.png

然后會顯示第三個(gè),即角色信息RoleArn,務(wù)必保管好,如下圖:


image.png

上圖中點(diǎn)擊開始授權(quán)之后便會生成一個(gè)RAM子賬號,生成該賬號之后進(jìn)入用戶管理頁面,如下圖,紅框中即為新建的RAM賬戶:


image.png

點(diǎn)擊上圖紅框中右側(cè)的授權(quán),彈出授權(quán)框:
我看右側(cè)紅框中的那個(gè)權(quán)限可以管理整個(gè)對象存儲服務(wù),所以就加了進(jìn)來,點(diǎn)擊確定即可:


image.png

至此,RAM子賬號就創(chuàng)建完畢了。

二、后端服務(wù)器:

1、安裝pythonSDK:
在安裝SDK之前需要先安裝python-devel庫,至于原因,可以去原文檔中查找,本文只講述實(shí)現(xiàn)過程。
在Ubuntu與Debian系統(tǒng)中安裝方式:

apt-get install python-dev

若因權(quán)限導(dǎo)致無法安裝,那就加sudo

開始安裝SKD:
通過pip方式安裝

pip install oss2

驗(yàn)證安裝版本:
進(jìn)入python的交互模式進(jìn)行如下操作,

>>> import oss2
>>> oss2.__version__

如果安裝無誤則應(yīng)該返回版本號,應(yīng)該是大于2版本的。
如果整個(gè)安裝過程有任何問題,請看原文檔的解決方案,一般不會有問題。

原文檔地址:
https://help.aliyun.com/document_detail/85288.html?spm=a2c4g.11186623.6.705.75404947Sj1KeS

2、向sts服務(wù)器請求stsToken:
首先需要有sts這個(gè)庫,只要一步安裝操作:

pip install aliyun-python-sdk-sts

下面就是在python中請求stsToken:

def getToken():

    # Endpoint以杭州為例,其它Region請按實(shí)際情況填寫。
    endpoint = 'oss-cn-hangzhou.aliyuncs.com'
    # 阿里云主賬號AccessKey擁有所有API的訪問權(quán)限,風(fēng)險(xiǎn)很高。強(qiáng)烈建議您創(chuàng)建并使用RAM賬號進(jìn)行API訪問或日常運(yùn)維,請登錄 https://ram.console.aliyun.com 創(chuàng)建RAM賬號。
    access_key_id = 'LTAIq*******'                   #替換成你的
    access_key_secret = 'wVlXxgdW*******'            #替換成你的
    bucket_name = '你的存儲空間名稱'                  #替換成你的
    # role_arn是角色的資源名稱。
    role_arn = 'acs:ram::16484498*******eratorrole'  #替換成你的

    clt = client.AcsClient(access_key_id, access_key_secret, 'cn-hangzhou')
    req = AssumeRoleRequest.AssumeRoleRequest()

    # 設(shè)置返回值格式為JSON。
    req.set_accept_format('json')
    req.set_RoleArn(role_arn)
    req.set_RoleSessionName('session-name')
    body = clt.do_action(req)

    # 使用RAM賬號的AccessKeyId和AccessKeySecret向STS申請臨時(shí)token,這個(gè)token將會傳給移動(dòng)端使用。
    stsToken = json.loads(body.decode())

    return stsToken

我返回給前端這個(gè)stsToken數(shù)據(jù)結(jié)構(gòu)如下圖所示:


stsToken數(shù)據(jù)結(jié)構(gòu)圖

移動(dòng)端就是要紅框中的四個(gè)字段,這四個(gè)字段必須要返回給移動(dòng)端保存,也不必管這個(gè)四個(gè)字段是干什么的。
至此,后端請求stsToken并將其返回給移動(dòng)端的授權(quán)過程結(jié)束。

三、移動(dòng)端(本文中為Android):
1、首先在gradle的dependencies中添加oss的依賴:

// 阿里云oss
implementation 'com.aliyun.dpa:oss-android-sdk:+'

原文檔中說在Maven項(xiàng)目中加入依賴,當(dāng)時(shí)感覺明顯是在gradle,難道是我孤陋寡聞了?就問了一下阿里那邊,最后表示就是gradle。

2、添加權(quán)限:
注意安卓6.0以后需要使用動(dòng)態(tài)權(quán)限,自行處理吧

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

3、添加混淆:
在proguard-rules.pro文件中添加:

-keep class com.alibaba.sdk.android.oss.** { *; }
-dontwarn okio.**
-dontwarn org.apache.commons.codec.binary.**

然后注意設(shè)置:

 release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }

4、然后就是在代碼中使用:

//請求后端返回StsToken
private void getSts(){
    basicsNetWorkAPI = HttpClient.create(BasicsNetWorkAPI.class);
    //請求后端返回stsToken的接口,每個(gè)人的網(wǎng)絡(luò)請求也許不一樣,因此,獲取的stsToken結(jié)果,請各自保存
    Call<StsServerBean> call = basicsNetWorkAPI.getStsToken();
    call.enqueue(new Callback<StsServerBean>() {
        @Override
        public void onResponse(retrofit2.Call<StsServerBean> call, Response<StsServerBean> response) {
            //上文中stsToken數(shù)據(jù)結(jié)構(gòu)圖中的紅框中的四個(gè)字段內(nèi)容被我封裝成一個(gè)Bean,為方便理解取名為stsTokenBean
            //為簡化理解,后文中所述stsToken為由該四個(gè)字段所組成,而不是前文的stsToken數(shù)據(jù)結(jié)構(gòu)圖的那一大坨json,因?yàn)槠渌侄斡貌坏?            StsTokenBean stsTokenBean = response.body().getCredentials();

            //請求成功后,獲取到那四個(gè)字段并保存到StsTokenBean后,應(yīng)該調(diào)用上傳文件的方法向OSS進(jìn)行上傳。
            //事實(shí)上,此處的StsTokenBean應(yīng)該保存到緩存,因?yàn)橐苿?dòng)端并不是每次上傳文件到OSS都需要請求stsToken的
            //因?yàn)槟菢泳蜁苈闊虼?,請求一次之后就會存在一個(gè)有效期,在有效期內(nèi)可以直接再次對OSS進(jìn)行操作,而上述四個(gè)參數(shù)中的Expiration即用來描述有效期的
            //你可以自行設(shè)置,在超過有效期后進(jìn)行重新獲取stsToken的操作,當(dāng)然若時(shí)間緊迫,你也可以按照本文的方式首先實(shí)現(xiàn)功能即可。后續(xù)改進(jìn)

            //上傳文件
            upload_file(stsTokenBean);
        }

        @Override
        public void onFailure(retrofit2.Call<StsServerBean> call, Throwable t) {

        }
    });
}

//上傳文件方法
private void upload_file(StsTokenBean stsTokenBean){
    //根據(jù)你的OSS的地區(qū)而自行定義,本文中的是杭州
    String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";

    //移動(dòng)端建議使用該方式,此時(shí),stsToken中的前三個(gè)參數(shù)就派上用場了
    OSSCredentialProvider credentialProvider = new OSSStsTokenCredentialProvider(stsTokenBean.getAccessKeyId(), stsTokenBean.getAccessKeySecret(), stsTokenBean.getSecurityToken());

    // 配置類如果不設(shè)置,會有默認(rèn)配置。
    ClientConfiguration conf = new ClientConfiguration();
    conf.setConnectionTimeout(15 * 1000);   // 連接超時(shí),默認(rèn)15秒。
    conf.setSocketTimeout(15 * 1000);       // socket超時(shí),默認(rèn)15秒。
    conf.setMaxConcurrentRequest(5);        // 最大并發(fā)請求數(shù),默認(rèn)5個(gè)。
    conf.setMaxErrorRetry(2);               // 失敗后最大重試次數(shù),默認(rèn)2次。

    //初始化OSS服務(wù)的客戶端oss
    //事實(shí)上,初始化OSS的實(shí)例對象,應(yīng)該具有與整個(gè)應(yīng)用程序相同的生命周期,在應(yīng)用程序生命周期結(jié)束時(shí)銷毀
    //但這里只是實(shí)現(xiàn)功能,若時(shí)間緊,你仍然可以按照本文方式先將功能實(shí)現(xiàn),然后優(yōu)化
    OSS oss = new OSSClient(getActivity().getApplicationContext(), endpoint, credentialProvider, conf);

    //當(dāng)前時(shí)間戳,用于自定義文件在OSS中存儲路徑末尾的名稱
    image_url_time = System.currentTimeMillis() + "";

    // 構(gòu)造上傳請求,第二個(gè)數(shù)參是ObjectName,第三個(gè)參數(shù)是本地文件路徑
    PutObjectRequest put = new PutObjectRequest("first-images", image_url_time, loacalFilePath);

    //異步上傳可以設(shè)置進(jìn)度回調(diào)
    put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
        @Override
        public void onProgress(PutObjectRequest request, long currentSize, long totalSize) {

            Log.i("上傳進(jìn)度:", "當(dāng)前進(jìn)度" + currentSize + "   總進(jìn)度" + totalSize);

        }
    });

    //實(shí)現(xiàn)異步上傳
    OSSAsyncTask task = oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
        @Override
        public void onSuccess(PutObjectRequest request, PutObjectResult result) {
            Log.d("PutObject", "UploadSuccess");
            Log.d("ETag", result.getETag());
            Log.d("RequestId", result.getRequestId());

            //這個(gè)image_url左邊的字符串部分是我OSS的Bucket的文件存儲地址,根據(jù)個(gè)人的文件存儲地址不同,替換成自己的即可,而后面的image_url_time則是為了區(qū)分每個(gè)文件的文件名
            //注意,最好的方式是設(shè)置回調(diào),因?yàn)榛卣{(diào)的功能必須要在線上服務(wù)器才能測試,我服務(wù)器在本地環(huán)境中是不允許回調(diào)的
            //在咨詢阿里云相關(guān)人員之后,他們說也允許記住地址,進(jìn)行拼接的方式保存線上文件url路徑
            //但是這種方式需要在OSS的管理控制臺中將你的存儲空間設(shè)置為公共讀的方式,不然沒法用下面的拼接鏈接。
            //此時(shí)你上傳的文件所在的線上地址就已經(jīng)獲得了,想怎么使用則隨意了
            image_url = "http://first********ngzhou.aliyuncs.com/" + image_url_time;
        }

        @Override
        public void onFailure(PutObjectRequest request, ClientException clientException, ServiceException serviceException) {
            if (clientException != null) {
                // 本地異常,如網(wǎng)絡(luò)異常等。
                clientException.printStackTrace();
            }
            if (serviceException != null) {
                // 服務(wù)異常。
                Log.e("ErrorCode", serviceException.getErrorCode());
                Log.e("RequestId", serviceException.getRequestId());
                Log.e("HostId", serviceException.getHostId());
                Log.e("RawMessage", serviceException.getRawMessage());
            }
        }
    });
    // 等異步上傳過程完成
    task.waitUntilFinished();
    Toast.makeText(getActivity(), "上傳成功", Toast.LENGTH_SHORT).show();

至此,移動(dòng)端的直接上傳文件到OSS的過程也結(jié)束了。你可以去自己的OSS控制臺看看是否新增了剛才上傳的文件。

整個(gè)OSS的集成過程完成!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容