阿里云文件存储OSS的后端与移动端集成

【写在前面】
建议初次接触OSS的童鞋可以根据本文自行操作一遍,能先实现功能,有时间的话再看阿里云OSS的文档,进行局部优化。那是一份什么样的文档的呢?就是你翻来覆去的看,然后你越看就越想把写文档的人拉过来揍一顿的感觉,总之谁看谁知道。
阅读本文时,需要注意本文中代码的注释内容;图片模糊问题不大,可以查看原图,而且只要能找准地方就行,我都打红框了。
【正文】
后端环境:ubuntu系统 + python
移动端: android
本文采用后端授权stsToken给移动端的方式,实现移动端文件直传OSS。
【整体流程描述】
移动端向后端发送获取stsToken的请求,后端接收到该请求后,于后端环境中执行请求OSS授权的stsToken的请求,然后将获取的stsToken返回给移动端,移动端获取stsToken后用以实例化OSSCredentialProvider,进而实例化OSS,通过OSS的实例化对象实现上传。
【整体流程图示】

阿里云文件存储OSS的后端与移动端集成
文章图片
移动端文件直传流程图 【实现过程】
一、在OSS控制台中:
1、首先创建Bucket空间:
进入OSS控制台中找到新建Bucket,然后点它。就行了
2、开通sts服务,如下图,进入你的OSS控制台,点击红框中前往RAM控制台

阿里云文件存储OSS的后端与移动端集成
文章图片
image.png
如下图,点击开始授权:

阿里云文件存储OSS的后端与移动端集成
文章图片
image.png
如果你之前没有创建过RAM账号,则此次创建之后会生成AccessKeyId、AccessKeySecret这两个密钥和RoleArn这个角色信息,此次请务必进行保管。如下图会先显示前二者: 阿里云文件存储OSS的后端与移动端集成
文章图片
image.png 然后会显示第三个,即角色信息RoleArn,务必保管好,如下图:

阿里云文件存储OSS的后端与移动端集成
文章图片
image.png 上图中点击开始授权之后便会生成一个RAM子账号,生成该账号之后进入用户管理页面,如下图,红框中即为新建的RAM账户:

阿里云文件存储OSS的后端与移动端集成
文章图片
image.png
点击上图红框中右侧的授权,弹出授权框:
我看右侧红框中的那个权限可以管理整个对象存储服务,所以就加了进来,点击确定即可:

阿里云文件存储OSS的后端与移动端集成
文章图片
image.png 至此,RAM子账号就创建完毕了。
二、后端服务器:
1、安装pythonSDK:
在安装SDK之前需要先安装python-devel库,至于原因,可以去原文档中查找,本文只讲述实现过程。
在Ubuntu与Debian系统中安装方式:

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的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建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数据结构如下图所示:

阿里云文件存储OSS的后端与移动端集成
文章图片
stsToken数据结构图 移动端就是要红框中的四个字段,这四个字段必须要返回给移动端保存,也不必管这个四个字段是干什么的。
至此,后端请求stsToken并将其返回给移动端的授权过程结束。
三、移动端(本文中为Android):
1、首先在gradle的dependencies中添加oss的依赖:
// 阿里云oss implementation 'com.aliyun.dpa:oss-android-sdk:+'

原文档中说在Maven项目中加入依赖,当时感觉明显是在gradle,难道是我孤陋寡闻了?就问了一下阿里那边,最后表示就是gradle。
2、添加权限:
注意安卓6.0以后需要使用动态权限,自行处理吧

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 call = basicsNetWorkAPI.getStsToken(); call.enqueue(new Callback() { @Override public void onResponse(retrofit2.Call call, Response response) { //上文中stsToken数据结构图中的红框中的四个字段内容被我封装成一个Bean,为方便理解取名为stsTokenBean //为简化理解,后文中所述stsToken为由该四个字段所组成,而不是前文的stsToken数据结构图的那一大坨json,因为其他字段用不到 StsTokenBean stsTokenBean = response.body().getCredentials(); //请求成功后,获取到那四个字段并保存到StsTokenBean后,应该调用上传文件的方法向OSS进行上传。 //事实上,此处的StsTokenBean应该保存到缓存,因为移动端并不是每次上传文件到OSS都需要请求stsToken的 //因为那样就会很麻烦,因次,请求一次之后就会存在一个有效期,在有效期内可以直接再次对OSS进行操作,而上述四个参数中的Expiration即用来描述有效期的 //你可以自行设置,在超过有效期后进行重新获取stsToken的操作,当然若时间紧迫,你也可以按照本文的方式首先实现功能即可。后续改进//上传文件 upload_file(stsTokenBean); }@Override public void onFailure(retrofit2.Call call, Throwable t) {} }); }//上传文件方法 private void upload_file(StsTokenBean stsTokenBean){ //根据你的OSS的地区而自行定义,本文中的是杭州 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); // 最大并发请求数,默认5个。 conf.setMaxErrorRetry(2); // 失败后最大重试次数,默认2次。//初始化OSS服务的客户端oss //事实上,初始化OSS的实例对象,应该具有与整个应用程序相同的生命周期,在应用程序生命周期结束时销毁 //但这里只是实现功能,若时间紧,你仍然可以按照本文方式先将功能实现,然后优化 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() { @Override public void onProgress(PutObjectRequest request, long currentSize, long totalSize) {Log.i("上传进度:", "当前进度" + currentSize + "总进度" + totalSize); } }); //实现异步上传 OSSAsyncTask task = oss.asyncPutObject(put, new OSSCompletedCallback() { @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则是为了区分每个文件的文件名 //注意,最好的方式是设置回调,因为回调的功能必须要在线上服务器才能测试,我服务器在本地环境中是不允许回调的 //在咨询阿里云相关人员之后,他们说也允许记住地址,进行拼接的方式保存线上文件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控制台看看是否新增了刚才上传的文件。
整个OSS的集成过程完成!

    推荐阅读