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

【写在前面】
建议初次接触OSS的童鞋可以根据本文自行操作一遍,能先实现功能,有时间的话再看阿里云OSS的文档,进行局部优化。那是一份什么样的文档的呢?就是你翻来覆去的看,然后你越看就越想把写文档的人拉过来揍一顿的感觉,总之谁看谁知道。

阅读本文时,需要注意本文中代码的注释内容;图片模糊问题不大,可以查看原图,而且只要能找准地方就行,我都打红框了。

【正文】
后端环境:ubuntu系统 + python
移动端: android

本文采用后端授权stsToken给移动端的方式,实现移动端文件直传OSS。

【整体流程描述】
移动端向后端发送获取stsToken的请求,后端接收到该请求后,于后端环境中执行请求OSS授权的stsToken的请求,然后将获取的stsToken返回给移动端,移动端获取stsToken后用以实例化OSSCredentialProvider,进而实例化OSS,通过OSS的实例化对象实现上传。

【整体流程图示】


移动端文件直传流程图

【实现过程】

一、在OSS控制台中:

1、首先创建Bucket空间:
进入OSS控制台中找到新建Bucket,然后点它。就行了

2、开通sts服务,如下图,进入你的OSS控制台,点击红框中前往RAM控制台


image.png

如下图,点击开始授权:


image.png

如果你之前没有创建过RAM账号,则此次创建之后会生成AccessKeyId、AccessKeySecret这两个密钥和RoleArn这个角色信息,此次请务必进行保管。如下图会先显示前二者:
image.png

然后会显示第三个,即角色信息RoleArn,务必保管好,如下图:


image.png

上图中点击开始授权之后便会生成一个RAM子账号,生成该账号之后进入用户管理页面,如下图,红框中即为新建的RAM账户:


image.png

点击上图红框中右侧的授权,弹出授权框:
我看右侧红框中的那个权限可以管理整个对象存储服务,所以就加了进来,点击确定即可:


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数据结构如下图所示:


stsToken数据结构图

移动端就是要红框中的四个字段,这四个字段必须要返回给移动端保存,也不必管这个四个字段是干什么的。
至此,后端请求stsToken并将其返回给移动端的授权过程结束。

三、移动端(本文中为Android):
1、首先在gradle的dependencies中添加oss的依赖:

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

原文档中说在Maven项目中加入依赖,当时感觉明显是在gradle,难道是我孤陋寡闻了?就问了一下阿里那边,最后表示就是gradle。

2、添加权限:
注意安卓6.0以后需要使用动态权限,自行处理吧

<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的操作,当然若时间紧迫,你也可以按照本文的方式首先实现功能即可。后续改进

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

        @Override
        public void onFailure(retrofit2.Call<StsServerBean> 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<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则是为了区分每个文件的文件名
            //注意,最好的方式是设置回调,因为回调的功能必须要在线上服务器才能测试,我服务器在本地环境中是不允许回调的
            //在咨询阿里云相关人员之后,他们说也允许记住地址,进行拼接的方式保存线上文件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的集成过程完成!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容