【寫在前面】
建議初次接觸OSS的童鞋可以根據本文自行操作一遍,能先實現功能遭垛,有時間的話再看阿里云OSS的文檔,進行局部優(yōu)化操灿。那是一份什么樣的文檔的呢锯仪?就是你翻來覆去的看,然后你越看就越想把寫文檔的人拉過來揍一頓的感覺趾盐,總之誰看誰知道庶喜。
閱讀本文時,需要注意本文中代碼的注釋內容救鲤;圖片模糊問題不大溃卡,可以查看原圖,而且只要能找準地方就行蜒简,我都打紅框了瘸羡。
【正文】
后端環(huán)境:ubuntu系統(tǒng) + python
移動端: android
本文采用后端授權stsToken給移動端的方式,實現移動端文件直傳OSS搓茬。
【整體流程描述】
移動端向后端發(fā)送獲取stsToken的請求犹赖,后端接收到該請求后,于后端環(huán)境中執(zhí)行請求OSS授權的stsToken的請求卷仑,然后將獲取的stsToken返回給移動端峻村,移動端獲取stsToken后用以實例化OSSCredentialProvider,進而實例化OSS锡凝,通過OSS的實例化對象實現上傳粘昨。
【整體流程圖示】
【實現過程】
一、在OSS控制臺中:
1、首先創(chuàng)建Bucket空間:
進入OSS控制臺中找到新建Bucket张肾,然后點它芭析。就行了
2、開通sts服務吞瞪,如下圖馁启,進入你的OSS控制臺,點擊紅框中前往RAM控制臺
如下圖芍秆,點擊開始授權:
如果你之前沒有創(chuàng)建過RAM賬號惯疙,則此次創(chuàng)建之后會生成AccessKeyId、AccessKeySecret這兩個密鑰和RoleArn這個角色信息妖啥,此次請務必進行保管霉颠。如下圖會先顯示前二者:
然后會顯示第三個,即角色信息RoleArn荆虱,務必保管好蒿偎,如下圖:
上圖中點擊開始授權之后便會生成一個RAM子賬號,生成該賬號之后進入用戶管理頁面克伊,如下圖酥郭,紅框中即為新建的RAM賬戶:
點擊上圖紅框中右側的授權华坦,彈出授權框:
我看右側紅框中的那個權限可以管理整個對象存儲服務愿吹,所以就加了進來,點擊確定即可:
至此惜姐,RAM子賬號就創(chuàng)建完畢了犁跪。
二、后端服務器:
1歹袁、安裝pythonSDK:
在安裝SDK之前需要先安裝python-devel庫坷衍,至于原因,可以去原文檔中查找条舔,本文只講述實現過程枫耳。
在Ubuntu與Debian系統(tǒng)中安裝方式:
apt-get install python-dev
若因權限導致無法安裝,那就加sudo
開始安裝SKD:
通過pip方式安裝
pip install oss2
驗證安裝版本:
進入python的交互模式進行如下操作孟抗,
>>> import oss2
>>> oss2.__version__
如果安裝無誤則應該返回版本號迁杨,應該是大于2版本的。
如果整個安裝過程有任何問題凄硼,請看原文檔的解決方案铅协,一般不會有問題。
原文檔地址:
https://help.aliyun.com/document_detail/85288.html?spm=a2c4g.11186623.6.705.75404947Sj1KeS
2摊沉、向sts服務器請求stsToken:
首先需要有sts這個庫狐史,只要一步安裝操作:
pip install aliyun-python-sdk-sts
下面就是在python中請求stsToken:
def getToken():
# Endpoint以杭州為例,其它Region請按實際情況填寫。
endpoint = 'oss-cn-hangzhou.aliyuncs.com'
# 阿里云主賬號AccessKey擁有所有API的訪問權限骏全,風險很高苍柏。強烈建議您創(chuàng)建并使用RAM賬號進行API訪問或日常運維,請登錄 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()
# 設置返回值格式為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申請臨時token鲁豪,這個token將會傳給移動端使用潘悼。
stsToken = json.loads(body.decode())
return stsToken
我返回給前端這個stsToken數據結構如下圖所示:
移動端就是要紅框中的四個字段,這四個字段必須要返回給移動端保存爬橡,也不必管這個四個字段是干什么的治唤。
至此,后端請求stsToken并將其返回給移動端的授權過程結束糙申。
三宾添、移動端(本文中為Android):
1、首先在gradle的dependencies中添加oss的依賴:
// 阿里云oss
implementation 'com.aliyun.dpa:oss-android-sdk:+'
原文檔中說在Maven項目中加入依賴柜裸,當時感覺明顯是在gradle缕陕,難道是我孤陋寡聞了?就問了一下阿里那邊疙挺,最后表示就是gradle扛邑。
2、添加權限:
注意安卓6.0以后需要使用動態(tài)權限铐然,自行處理吧
<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.**
然后注意設置:
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
4、然后就是在代碼中使用:
//請求后端返回StsToken
private void getSts(){
basicsNetWorkAPI = HttpClient.create(BasicsNetWorkAPI.class);
//請求后端返回stsToken的接口搀暑,每個人的網絡請求也許不一樣沥阳,因此,獲取的stsToken結果自点,請各自保存
Call<StsServerBean> call = basicsNetWorkAPI.getStsToken();
call.enqueue(new Callback<StsServerBean>() {
@Override
public void onResponse(retrofit2.Call<StsServerBean> call, Response<StsServerBean> response) {
//上文中stsToken數據結構圖中的紅框中的四個字段內容被我封裝成一個Bean桐罕,為方便理解取名為stsTokenBean
//為簡化理解,后文中所述stsToken為由該四個字段所組成桂敛,而不是前文的stsToken數據結構圖的那一大坨json功炮,因為其他字段用不到
StsTokenBean stsTokenBean = response.body().getCredentials();
//請求成功后,獲取到那四個字段并保存到StsTokenBean后埠啃,應該調用上傳文件的方法向OSS進行上傳死宣。
//事實上,此處的StsTokenBean應該保存到緩存碴开,因為移動端并不是每次上傳文件到OSS都需要請求stsToken的
//因為那樣就會很麻煩毅该,因次博秫,請求一次之后就會存在一個有效期,在有效期內可以直接再次對OSS進行操作眶掌,而上述四個參數中的Expiration即用來描述有效期的
//你可以自行設置挡育,在超過有效期后進行重新獲取stsToken的操作,當然若時間緊迫朴爬,你也可以按照本文的方式首先實現功能即可即寒。后續(xù)改進
//上傳文件
upload_file(stsTokenBean);
}
@Override
public void onFailure(retrofit2.Call<StsServerBean> call, Throwable t) {
}
});
}
//上傳文件方法
private void upload_file(StsTokenBean stsTokenBean){
//根據你的OSS的地區(qū)而自行定義,本文中的是杭州
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
//移動端建議使用該方式召噩,此時母赵,stsToken中的前三個參數就派上用場了
OSSCredentialProvider credentialProvider = new OSSStsTokenCredentialProvider(stsTokenBean.getAccessKeyId(), stsTokenBean.getAccessKeySecret(), stsTokenBean.getSecurityToken());
// 配置類如果不設置,會有默認配置具滴。
ClientConfiguration conf = new ClientConfiguration();
conf.setConnectionTimeout(15 * 1000); // 連接超時凹嘲,默認15秒。
conf.setSocketTimeout(15 * 1000); // socket超時构韵,默認15秒周蹭。
conf.setMaxConcurrentRequest(5); // 最大并發(fā)請求數,默認5個疲恢。
conf.setMaxErrorRetry(2); // 失敗后最大重試次數凶朗,默認2次。
//初始化OSS服務的客戶端oss
//事實上显拳,初始化OSS的實例對象棚愤,應該具有與整個應用程序相同的生命周期,在應用程序生命周期結束時銷毀
//但這里只是實現功能萎攒,若時間緊遇八,你仍然可以按照本文方式先將功能實現矛绘,然后優(yōu)化
OSS oss = new OSSClient(getActivity().getApplicationContext(), endpoint, credentialProvider, conf);
//當前時間戳耍休,用于自定義文件在OSS中存儲路徑末尾的名稱
image_url_time = System.currentTimeMillis() + "";
// 構造上傳請求,第二個數參是ObjectName,第三個參數是本地文件路徑
PutObjectRequest put = new PutObjectRequest("first-images", image_url_time, loacalFilePath);
//異步上傳可以設置進度回調
put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
@Override
public void onProgress(PutObjectRequest request, long currentSize, long totalSize) {
Log.i("上傳進度:", "當前進度" + currentSize + " 總進度" + totalSize);
}
});
//實現異步上傳
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());
//這個image_url左邊的字符串部分是我OSS的Bucket的文件存儲地址货矮,根據個人的文件存儲地址不同羊精,替換成自己的即可,而后面的image_url_time則是為了區(qū)分每個文件的文件名
//注意囚玫,最好的方式是設置回調喧锦,因為回調的功能必須要在線上服務器才能測試,我服務器在本地環(huán)境中是不允許回調的
//在咨詢阿里云相關人員之后抓督,他們說也允許記住地址燃少,進行拼接的方式保存線上文件url路徑
//但是這種方式需要在OSS的管理控制臺中將你的存儲空間設置為公共讀的方式,不然沒法用下面的拼接鏈接铃在。
//此時你上傳的文件所在的線上地址就已經獲得了阵具,想怎么使用則隨意了
image_url = "http://first********ngzhou.aliyuncs.com/" + image_url_time;
}
@Override
public void onFailure(PutObjectRequest request, ClientException clientException, ServiceException serviceException) {
if (clientException != null) {
// 本地異常碍遍,如網絡異常等。
clientException.printStackTrace();
}
if (serviceException != null) {
// 服務異常阳液。
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();
至此怕敬,移動端的直接上傳文件到OSS的過程也結束了。你可以去自己的OSS控制臺看看是否新增了剛才上傳的文件帘皿。
整個OSS的集成過程完成东跪!