阿里云oss文件分片、断点续传上传
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文件分片、断点续传上传相关推荐
- 阿里云oss权限控制,上传下载测试
2019独角兽企业重金招聘Python工程师标准>>> 列子公共读: 新建一个bucket - > data 存储目录 新建读写账号 -> 访问控制RAM -> 权 ...
- vue直传图片到阿里云OSS(单张直接上传)
背景: 近期项目使用到多图片上传功能,常规的调用后端接口上传,可能会出现上传速度慢,体验不佳的情况.那么就考虑另一种上传方式.由前端直接上传到oss.快的一匹... 经过摸索,也实现了.代码其实没啥难 ...
- JAVA通过阿里云OSS存储实现图片上传功能
一.前置准备 首先我们需要在阿里云注册账号,实名认证后开通OSS功能,点击进入OSS功能的管理平台 进入概览页面后,点击Bucket列表,创建一个Bucket(相当于一个存放文件的文件夹) 关键是要 ...
- Typora+阿里云OSS(将图片上传到阿里云服务器上)
1..阿里云OSS搭配PicGo实现图床 1.1.PicoGO 首先去PicGo官网下载 PicGo 一下,安装后打开如下: 2.2.阿里云对象存储OSS购买和配置 阿里云->产品->对象 ...
- 阿里云OSS对象存储 , js 上传文件
function uploadFile2(){// 上传后的文件路径和文件名var fileName = "20220420/使用ajax上传图片.jpg";// 获取oss上传令 ...
- 阿里云OSS对象存储服务上传失败问题之一
简介: OSS是阿里云提供一个对象存储服务,有着稳定高效的特点,但在操作时有些问题还是必须要注意一下的 今天在进行上传头像的操作时,发生了一个OSS连接时出现的问题,导致头像上传失败,问题的样式如下图 ...
- 一步实现阿里云OSS二进制流图片上传
/*** 上传object至OSS* @param $content* @param string $fileName* @return array*/public static function p ...
- 11月16日云栖精选夜读:阿里云 oss JavaScript客户端签名文件上传 vue2.0
2019独角兽企业重金招聘Python工程师标准>>> 官方文档地址https://help.aliyun.com/document_detail/31925.html?spm=51 ...
- Linux环境Shell脚本上传下载阿里云OSS文件
为什么80%的码农都做不了架构师?>>> Linux环境Shell脚本上传下载阿里云OSS文件 背景 工作中由于我们项目生成的日志文件比较重要,而本地磁盘空间有限存储不了多久, ...
- SpringBoot整合阿里云OSS文件上传、下载、查看、删除
SpringBoot整合阿里云OSS文件上传.下载.查看.删除 该项目源码地址:https://github.com/ggb2312/springboot-integration-examples ( ...
最新文章
- 相邻帧差法和三帧差法
- python好学吗mooc中文网-用Python玩转数据
- And it's over,And it's a new start
- mongodb 安装、开启服务 和 php添加mongodb扩展
- java.util.concurrent.Exchanger应用范例与原理浅析--转载
- java中super()_Java 泛型中 extends 和 super 的区别是什么?
- CVE-2021-40444 0 day漏洞利用
- wxWidgets:wxCmdLineParser类用法
- 深度学习(五十三)对抗网络
- Node.js入门以及第一个helloworld程序.
- 如何追求高质量的代码?
- 混淆矩阵confusion matrix
- 数据库mysql,oracle,sqlite,mariadb 相关收藏
- jq onclick 定义_jq中的onclick绑定事件
- 隐私计算--21--分布式机器学习
- 李飞飞、吴恩达、Bengio等人的15大顶级深度学习课程(转)
- MindSpore21天实战营(1):基于MindSpore Lite开发目标检测的安卓APP实战
- CVTE 2022届实习生 Web后台开发笔试
- 博客之星2018 ,请为我投上您宝贵的一票!
- origin画对数坐标_如何用Origin绘制对数坐标图、双横坐标图及插入到Word文稿