1、概述

把文件上传到阿里云oss上有两种上传方案:
(1) 表单提交
(2)阿里云sdk
表单提交操作简单只需要向bucket所在地址发起post请求,并携带上签名,具体的可以由javaScript在前端生成,或者是由自己项目服务端生成,上传文件时需要先获取签名然后再携带上签名的参数向oss服务器上传文件。表单操作便捷,但有三大痛点,第一点是它不支持断点重传,第二它不支持分片上传,第三,它对批量上传不太友好,我曾经实践过,使用表单提交获取的签名只能使用一次,要想通过表单提交来实现批量上传,说白了就是要上传每一个文件时都要先去获取签名,然后再向oss服务器发起一次新的post请求.
吐槽完了表单提交,再来说说今天的主角阿里云sdk,它支持分片上传和断点续传更加适合真实项目的使用场景。其次对于当前的前后端分离架构文件上传的安全问题,阿里云sdk的解决方案是STS临时访问令牌,这个访问令牌是临时性的,每一次生成都是不同的,并且可以设置过期时间,且前端可以缓存起来重复利用的。它的安全性也是更高的,STS生成的流程是:应用服务器携带者直接身份信息去请求阿里云的STS服务器,STS服务器生成临时访问令牌返回给应用服务器,应用服务器再将令牌以及bucket信息封装返回给前端,前端在再拿着应用服务器返回的令牌去操作oss服务器上文件。
ok,流程捋完,开始动手实践。

2、创建RAM用户 角色 权限策略

(1) 进入到oss控制台点击权限管理
(2)点击前往控制套进入到RAM管理控制台


(3) 选择用户模块,创建新的用户

(4)输入用户名,重点是勾上 Open API调用访问

(5) 点击确定后将出现如下界面

(6)保存AccessKey Id 和 AccessKey Secret
可以直接保存到后端的配置文件里,待会获得STS Token 的时候要用到。
保存之后点击返回。
(7) 选择角色模块,点击创建新的角色

此时将会出现如图界面

选择可信实体类型为 阿里云账号,点击下一步。输入角色名称,点击完成即可。

找到刚刚创建的角色,点击角色名,将会看到如下页面,需要保存ARN,同前面的AccessKey 一样需要在获取令牌的时候用到。

(8)创建允许上传文件的权限。 进入权限策略管理,点击创建权限策略,输入策略名称,选择脚本配置,脚本内容可参考。

    "Version": "1","Statement": [{"Effect": "Allow","Action": ["oss:PutObject"],"Resource": ["acs:oss:*:*:examplebucket/exampledir","acs:oss:*:*:examplebucket/exampledir/*"]}]
}


配置完脚本文件后,点击确认并返回
(9) 为用户和角色分配权限
进入到用户模块,点击刚刚创建的用户对用的添加权限

将会出现如下界面

搜索sts,点击AliyunSTSAssumRoleAccess ,它将会出现在已选择的框中,点击确定。

进入到角色模块,找到刚刚创建的角色,点击添加权限

和为用户分配权健的界面相同,选择自定义策略,添加刚刚创建的策略。

总结一下,就是需要一个RAM用户一个角色,一个允许文件上传到对应bucket的权限策略,在请求token的时候需要带上accessKeyId和accessKeySecret相当于RAM的账号密码,同时需要带上角色名和角色ARN,通过角色来为token 授予bucket的访问权限;

2.应用服务端向STS服务器请求Token

如果是SpringBoot项目的话需要引入依赖:

<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-sts</artifactId><version>3.0.0</version></dependency><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>4.4.6</version></dependency>

如果是SpringCloud项目只需要引入:

 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alicloud-oss</artifactId></dependency>

引入了依赖之后开始编写获取StsToken的代码,首先定义一个StsToken实体,用来反馈给前端:

@Data
@Builder
public class StsTokenVo {private String region;private String accessKeyId;private String accessKeySecret;private String stsToken;private String bucket;private String expiration;}

按部就班,来个Service

public interface StsTokenService {StsTokenVo getStsToken();}
@Service
public class StsTokenServiceImpl implements StsTokenService {private static final String REGION = "oss-cn-beijing";private static final String BUCKET = "chiris-test";private static final String ENDPOINT = "sts.cn-beijing.aliyuncs.com";private static final String ACCESS_KEY_ID = "access key id";private static final String ACCESS_KEY_SECRET = "acccess key secret";private static final String ROLE_ARN = "role arn";private static final String ROLE_SESSION_NAME = "roleName";private static final String POLICY = "{\n" +"    \"Version\": \"1\", \n" +"    \"Statement\": [\n" +"        {\n" +"            \"Action\": [\n" +"                \"oss:PutObject\"\n" +"            ], \n" +"            \"Resource\": [\n" +"                \"acs:oss:*:*:bucket-name/*\" \n" +"            ], \n" +"            \"Effect\": \"Allow\"\n" +"        }\n" +"    ]\n" +"}";@Overridepublic StsTokenVo getStsToken() {try {DefaultProfile.addEndpoint("", "", "Sts", ENDPOINT);DefaultProfile profile = DefaultProfile.getProfile("", ACCESS_KEY_ID, ACCESS_KEY_SECRET);DefaultAcsClient client = new DefaultAcsClient(profile);AssumeRoleRequest request = new AssumeRoleRequest();request.setSysMethod(MethodType.POST);request.setRoleArn(ROLE_ARN);request.setRoleSessionName(ROLE_SESSION_NAME);request.setPolicy(POLICY);request.setDurationSeconds(3600L);final AssumeRoleResponse response = client.getAcsResponse(request);String expiration = response.getCredentials().getExpiration();String accessKeyId = response.getCredentials().getAccessKeyId();String accessKeySecret = response.getCredentials().getAccessKeySecret();String stsToken = response.getCredentials().getSecurityToken();StsTokenVo token = StsTokenVo.builder().region(REGION).bucket(BUCKET).accessKeyId(accessKeyId).accessKeySecret(accessKeySecret).stsToken(stsToken).expiration(expiration).build();return token;} catch (ClientException e) {e.printStackTrace();}return null;}
}

再来个controller

@RestController
@RequestMapping("/sts")
public class StsTokenController {@Resourceprivate StsTokenService stsTokenService;@GetMapping("")@CrossOriginpublic StsTokenVo getStsToken(HttpServletResponse response) throws IOException {StsTokenVo stsToken = stsTokenService.getStsToken();if (stsToken != null){return stsToken;}response.setStatus(500);response.getWriter().println("get sts token failed");return null;}
}

测试一下:

返回的结果中会生成一个临时的accessKeyId, accessKeySecret 以及一个临时的SecurityToken,同时也需要封装一下bucket和域名,这样的话可以在后端配置,不用在前端写死。

3. Vue.js 实现分片上传与断点上传

获取到stsToken后,就可以来做分片上传与断点上传啦!利用阿里云sdk实现文件分片上传很简单。
(1) 安装依赖

npm install ali-oss --save。

(2) 需要一个文件上传的组件,这里使用element-ui的el-upload组件

<template><div class="upload"><el-uploadclass="upload-demo"drag:auto-upload="false"action="":file-list="fileList":on-change="onChange"multiple><i class="el-icon-upload"></i><div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div></el-upload><el-button @click="doUpload">upload</el-button><el-button @click="resume"> continue</el-button></div>
</template>
在这里插入代码片

(3)引入OSS 对象,并申明一个全局变量ossClient 和 tempCheckPoint (数组,记录了已经完成上传的分片及其对应的etag)如果将ossClient申明为vue的属性,可以完成上传,但是无法实现断点续传,具体的原因应该是和Vue的生命周期有关。

const OSS = require('ali-oss')
let  ossClient
let tempCheckpoint

(4) 每次上传时最好是能重新new 一个ossClient,上传以前需要先获取StsToken,在项目中可以将StsToken根据他的过期时间缓存在cookie中,避免不必要的网络请求,分片上传和断点续传主要是使用multipartUpload,方法

async doMultipartUpload() {try{let file = this.fileList[0].rawlet key = '/test/' + file.namelet result = await ossClient.multipartUpload(key, file, {progress: function (p, checkpoint) {tempCheckpoint = checkpointconsole.log( "p: " + p)     // 打印上传百分比console.log(tempCheckpoint)},})console.log('result : ')console.log(result)console.log('check point')console.log(tempCheckpoint)} catch (e) {console.log(e)console.log(tempCheckpoint)}},

(5)断点续传

async resume() {let file = this.fileList[0].rawlet key = '/test/' + file.namelet result = await ossClient.multipartUpload(key, file, {progress: function (p, checkpoint) {tempCheckpoint = checkpointconsole.log(p)},checkpoint: tempCheckpoint})console.log('resumeUpload success')console.log(result)},

断点续传时需要携带上之前保存的tempCheckPoint,具体如何保存看实际应用场景。multipartUpload方法的更多参数可以参见 参数说明checkpoint 的结构如下图所示:

其中donePart保存了已经上传的分片

4. 总结

观察控制台可以看到分文件被拆分成了多个分片并行的上传,再在开始上传时客户端会先发送一个初始化的请求,并生成一个全局id

全部非分片上传完成之后,客户端会发送最后一个合并请求。oss服务器会根据全局uploadID和partNumber来合并文件碎片。
重要: 使用aliyun-sdk需要对bucket做跨域配置,如下:否则会报没有权限的错误!

5.完整代码

<template><div class="upload"><el-uploadclass="upload-demo"drag:auto-upload="false"action="":file-list="fileList":on-change="onChange"multiple><i class="el-icon-upload"></i><div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div></el-upload><el-button @click="doUpload">upload</el-button><el-button @click="resume"> continue</el-button></div>
</template><script>import http from "../util/http";const OSS = require('ali-oss')let  ossClientlet tempCheckpointexport default {name: "Upload",data() {return {fileList:[],ossConfig: {},}},methods: {async doUpload() {if (this.fileList.length === 0) {alert("please select file")return}if (ossClient == null){let ossConfigawait this.getStsToken().then(res => {if (res.status === 200) {let data = res.dataossConfig = {region: data.region,accessKeyId: data.accessKeyId,accessKeySecret: data.accessKeySecret,stsToken: data.stsToken,bucket: data.bucket}} else {alert('sts token get failed')}})ossClient = new OSS(ossConfig)}await this.doMultipartUpload()},onChange(file) {this.fileList[0] = file},getStsToken() {return http({method: 'get',url: '/sts'})},async doMultipartUpload() {try{let file = this.fileList[0].rawlet key = '/test/' + file.namelet result = await ossClient.multipartUpload(key, file, {progress: function (p, checkpoint) {tempCheckpoint = checkpointconsole.log( "p: " + p)     // 打印上传百分比console.log(tempCheckpoint)},partsSize: 1000 * 1024 * 1024})console.log('result : ')console.log(result)console.log('check point')console.log(tempCheckpoint)} catch (e) {console.log(e)console.log(tempCheckpoint)}},async resume() {let file = this.fileList[0].rawlet key = '/test/' + file.namelet result = await ossClient.multipartUpload(key, file, {progress: function (p, checkpoint) {tempCheckpoint = checkpointconsole.log(p)},partSize: 50 * 1024 * 1024,checkpoint: tempCheckpoint})console.log('resumeUpload success')console.log(result)},},}
</script><style scoped type="less">.upload{width: 400px;height: 300px;}
</style>

阿里云oss文件分片、断点续传上传相关推荐

  1. 阿里云oss权限控制,上传下载测试

    2019独角兽企业重金招聘Python工程师标准>>> 列子公共读: 新建一个bucket - > data 存储目录 新建读写账号 -> 访问控制RAM -> 权 ...

  2. vue直传图片到阿里云OSS(单张直接上传)

    背景: 近期项目使用到多图片上传功能,常规的调用后端接口上传,可能会出现上传速度慢,体验不佳的情况.那么就考虑另一种上传方式.由前端直接上传到oss.快的一匹... 经过摸索,也实现了.代码其实没啥难 ...

  3. JAVA通过阿里云OSS存储实现图片上传功能

    一.前置准备 首先我们需要在阿里云注册账号,实名认证后开通OSS功能,点击进入OSS功能的管理平台 进入概览页面后,点击Bucket列表,创建一个Bucket(相当于一个存放文件的文件夹)  关键是要 ...

  4. Typora+阿里云OSS(将图片上传到阿里云服务器上)

    1..阿里云OSS搭配PicGo实现图床 1.1.PicoGO 首先去PicGo官网下载 PicGo 一下,安装后打开如下: 2.2.阿里云对象存储OSS购买和配置 阿里云->产品->对象 ...

  5. 阿里云OSS对象存储 , js 上传文件

    function uploadFile2(){// 上传后的文件路径和文件名var fileName = "20220420/使用ajax上传图片.jpg";// 获取oss上传令 ...

  6. 阿里云OSS对象存储服务上传失败问题之一

    简介: OSS是阿里云提供一个对象存储服务,有着稳定高效的特点,但在操作时有些问题还是必须要注意一下的 今天在进行上传头像的操作时,发生了一个OSS连接时出现的问题,导致头像上传失败,问题的样式如下图 ...

  7. 一步实现阿里云OSS二进制流图片上传

    /*** 上传object至OSS* @param $content* @param string $fileName* @return array*/public static function p ...

  8. 11月16日云栖精选夜读:阿里云 oss JavaScript客户端签名文件上传 vue2.0

    2019独角兽企业重金招聘Python工程师标准>>> 官方文档地址https://help.aliyun.com/document_detail/31925.html?spm=51 ...

  9. Linux环境Shell脚本上传下载阿里云OSS文件

    为什么80%的码农都做不了架构师?>>>    Linux环境Shell脚本上传下载阿里云OSS文件 背景 工作中由于我们项目生成的日志文件比较重要,而本地磁盘空间有限存储不了多久, ...

  10. SpringBoot整合阿里云OSS文件上传、下载、查看、删除

    SpringBoot整合阿里云OSS文件上传.下载.查看.删除 该项目源码地址:https://github.com/ggb2312/springboot-integration-examples ( ...

最新文章

  1. 相邻帧差法和三帧差法
  2. python好学吗mooc中文网-用Python玩转数据
  3. And it's over,And it's a new start
  4. mongodb 安装、开启服务 和 php添加mongodb扩展
  5. java.util.concurrent.Exchanger应用范例与原理浅析--转载
  6. java中super()_Java 泛型中 extends 和 super 的区别是什么?
  7. CVE-2021-40444 0 day漏洞利用
  8. wxWidgets:wxCmdLineParser类用法
  9. 深度学习(五十三)对抗网络
  10. Node.js入门以及第一个helloworld程序.
  11. 如何追求高质量的代码?
  12. 混淆矩阵confusion matrix
  13. 数据库mysql,oracle,sqlite,mariadb 相关收藏
  14. jq onclick 定义_jq中的onclick绑定事件
  15. 隐私计算--21--分布式机器学习
  16. 李飞飞、吴恩达、Bengio等人的15大顶级深度学习课程(转)
  17. MindSpore21天实战营(1):基于MindSpore Lite开发目标检测的安卓APP实战
  18. CVTE 2022届实习生 Web后台开发笔试
  19. 博客之星2018 ,请为我投上您宝贵的一票!
  20. origin画对数坐标_如何用Origin绘制对数坐标图、双横坐标图及插入到Word文稿

热门文章

  1. python联合vrep_python控制vrep代码实例
  2. Clover 驱动文件夹_Intel全系利核显驱动教程
  3. 【C语言应用】使用查表法计算CRC8
  4. 一个方便快捷gif在线水印制作(支持文字和图片)
  5. PDF怎么把两个合并成一个?PDF怎么合并?
  6. 优秀软件测试工程师必读书籍推荐
  7. 【开源项目】CircuitJS1在线电路仿真
  8. Windows的文件目录管理策略
  9. 一文搞定十大排序算法(细)
  10. AngularJs--ng-repeate渲染完毕后执行的代码