阿里云OSS使用RAM生成STS分片上传大文件Demo
Posted 赵侠客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阿里云OSS使用RAM生成STS分片上传大文件Demo相关的知识,希望对你有一定的参考价值。
阿里云普通Form表单上传视频
这是最简单的一种上传方式,使用后台生成Token 前端通过Form表单直传OSS服务器
后台生成Token代码
/**
* 生成阿里云上传Token
* @return
* @throws UnsupportedEncodingException
*/
@GetMapping("/token")
public ResponseEntity<ApiResult> token() throws UnsupportedEncodingException
//上传地址
String uploadUrl = "http://bucketName.oss-cn-hangzhou.aliyuncs.com/";
String dir = "";
OSSClient client = new OSSClient(STSUtil.END_POINT, STSUtil.accessKeyId, STSUtil.accessKeySecret);
long expireEndTime = System.currentTimeMillis() + STSUtil.expirationTime * 1000;
Date expiration = new Date(expireEndTime);
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
String postPolicy = client.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = client.calculatePostSignature(postPolicy);
//OSS文件名
String key = String.format("%s.mp4", UidUtils.generateObjectId());
JSONObject jasonCallback = new JSONObject();
//你的回调URL
jasonCallback.put("callbackUrl", "http://a.com/endpoint/aliyun/uploadSuccess");
//阿里云回调返回参数
jasonCallback.put("callbackBody", "id=" + key + "&filename=$object&type=video&etag=$etag&size=$size&mimeType=$mimeType");
jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
Map<String, String> res = new HashMap<>();
res.put("callback", base64CallbackBody);
res.put("key", key);
res.put("OSSAccessKeyId", STSUtil.accessKeyId);
res.put("policy", encodedPolicy);
res.put("success_action_status", "200");
res.put("signature", postSignature);
res.put("dir", dir);
res.put("uploadUrl", uploadUrl);
res.put("expire", String.valueOf(expireEndTime / 1000));
return renderOk(res);
//返回数据
"code": 0,
"data":
"OSSAccessKeyId": "LTAI4GHdsbaaaaJhK",
"uploadUrl": "http://bucketName.oss-cn-hangzhou.aliyuncs.com/",
"signature": "XdVOT2/HiOals03pQjBaR16Cd9o=",
"success_action_status": "200",
"expire": "1616640488",
"callback": "eyJjYWxsYmFja0JvZmaamdHlwsmV9Jm1pbWVUeXBlPSR7bWltZVR5cGV9In0=",
"dir": "",
"key": "6688924142276.mp4",
"policy": "eyJleHBpcmF0aW9uIjOC42MzBaIiiXV19"
前端通过表单上传
<div class="main">
<input onchange="getToken()"
accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx" id="file" name="file"
class="ipt" type="file"/>
</div>
<script>
function getToken()
var xhr = new XMLHttpRequest();
xhr.open('POST', "/token", true);
var formData = new FormData();
xhr.onload = function (e)
var res = JSON.parse(this.responseText);
if (res.code == 0)
uploadFile(res, file);
;
xhr.send(formData);
function uploadFile(data, file)
var xhr = new XMLHttpRequest();
xhr.open('POST', data.uploadUrl, true);
var formData, startDate;
formData = new FormData();
imgInfoId = data.id;
formData.append("key",data.key)
formData.append('policy', data.policy);
formData.append('OSSAccessKeyId', data.OSSAccessKeyId);
formData.append('success_action_status',200);
formData.append('callback',data.callback);
formData.append('signature',data.signature);
formData.append('file', file.files[0]);
var taking;
xhr.upload.addEventListener("progress", function (evt)
if (evt.lengthComputable)
var nowDate = new Date().getTime();
taking = nowDate - startDate;
var x = (evt.loaded) / 1024;
var y = taking / 1000;
var uploadSpeed = (x / y);
var formatSpeed;
if (uploadSpeed > 1024)
formatSpeed = (uploadSpeed / 1024).toFixed(2) + "Mb\\/s";
else
formatSpeed = uploadSpeed.toFixed(2) + "Kb\\/s";
var percentComplete = Math.round(evt.loaded * 100 / evt.total);
//计算进度及速度
console.log(percentComplete, ",", formatSpeed);
, false);
xhr.onreadystatechange = function (response)
if (xhr.readyState == 4 && xhr.status == 200 && xhr.responseText != "")
console.info("success")
else if (xhr.status != 200 && xhr.responseText)
console.info("error")
;
startDate = new Date().getTime();
xhr.send(formData);
</script>
方法特点
这种上传方式容易简单,缺点是上传速度慢,不支持大文件上传,文件大小数量在G级别的无法使用,而且容易造成浏览器卡顿,所以大文件需要使用分片上传
STS分片上传
配置RAM
1.RAM创建用户,并生成AK SK,上传时使用这组AK/SK
同时给这个用户分配 生成STS和控制OSS权限
AliyunSTSAssumeRoleAccess
AliyunOSSFullAccess
2.创建RAM角色,给ARN分配
3.Bucket配置 OSS跨域增加Etag及x-oss-request-id 暴露Headers 允许跨越上传
后端生成STS Token
/**
* 生成STS token
* @return
* @throws ClientException
*/
@GetMapping("/sts")
public ResponseEntity<ApiResult> sts() throws ClientException
Map<String, Object> response = new HashMap<>();
Map<String, Object> callback = new HashMap<>();
callback.put("callbackBodyType", "application/x-www-form-urlencoded");
callback.put("callbackUrl", "http://a.com/endpoint/aliyun/uploadSuccess");
callback.put("callbackBody", "id=123123123&filename=$object&type=video&etag=$etag&size=$size&mimeType=$mimeType");
AssumeRoleResponse.Credentials credentials = STSUtil.createSTSForPutObject(STSUtil.bucketName, STSUtil.ROLE_ARN, STSUtil.accessKeyId, STSUtil.accessKeySecret, STSUtil.expirationTime);
Map<String, Object> res = mapOf("credentials", credentials, "fileKey", UidUtils.generateObjectId() + ".mp4", "bucket", STSUtil.bucketName, "region", STSUtil.REGION_CN_HANGZHOU, "endpoint", STSUtil.END_POINT);
response.put("callback", callback);
response.putAll(res);
return renderOk(response);
前端分片上传
<html>
<head>
<script src="https://meizi-tm-5108-pub.oss-cn-hangzhou.aliyuncs.com/lib/aliyun-upload-sdk/lib/aliyun-oss-sdk-6.13.0.min.js"></script>
<script src="https://meizi-tm-5108-pub.oss-cn-hangzhou.aliyuncs.com/lib/aliyun-upload-sdk/lib/base64.js"></script>
</head>
<body>
<input type="file" id="file"/>
<span id="process"></span>
<span id="res"></span>
<script type="text/javascript">
document.getElementById('file').addEventListener('change', function (e)
var file = e.target.files[0];
//获取STS
OSS.urllib.request("/sts",
method: 'GET',
function (err, response)
if (err)
return alert(err);
try
result = JSON.parse(response);
catch (e)
return alert('parse sts response info error: ' + e.message);
//64位编码
var parses = function (data)
var base = new Base64();
return base.encode(JSON.stringify(data));
var client = new OSS(
accessKeyId: result.data.credentials.accessKeyId,
accessKeySecret: result.data.credentials.accessKeySecret,
stsToken: result.data.credentials.securityToken,
endpoint: result.data.endpoint,
bucket: result.data.bucket,
region: result.data.region,
);
client.multipartUpload(result.data.fileKey, file,
parallel: 4,
partSize: 1024 * 1024,
mime: 'video/mp4',
headers:
'x-oss-callback': parses(result.data.callback)
,
progress: function (p, checkpoint)
document.getElementById('process').innerHTML = p * 100 + "%";
).then(function (result)
console.log(result);
document.getElementById('res').innerHTML = "上传成功:" + JSON.parse(result).data.filename;
).catch(function (err)
console.log(err);
);
);
);
</script>
</body>
</html>
完成分片上传
调通过程中遇到了很多和权限相关的问题,阿里这个RAM确实有点复杂,第一次上手有点门槛,不过这套权限管控确实很好,可以精确控制生成的AK/SK访问云上任意资源的 CRUD权限,安全性是得到保障的。
STSUtil.java
package com.zjrb.media.base.util.aliyun;
import com.alibaba.fastjson.JSON;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse.Credentials;
import java.io.File;
/**
* @version 1.0
* @describe: OSS临时访问凭证授权
* @author:houkai
* @Date: 2018/3/7 14:54
*/
public class STSUtil
/**
* 目前只有"cn-hangzhou"这个region可用, 不要使用填写其他region的值
*/
public static final String REGION_CN_HANGZHOU = "cn-hangzhou";
/**
* 当前 STS API 版本
*/
public static final String STS_API_VERSION = "2015-04-01";
/**
* 必须是https请求
*/
public static final ProtocolType PROTOCOL_TYPE = ProtocolType.HTTPS;
/**
* 指定角色的全局资源描述符(Aliyun Resource Name,简称Arn)
*/
public static final String ROLE_ARN = "acs:ram::1717083:role/media-upload";
/**
* 用户自定义参数。此参数用来区分不同的Token,可用于用户级别的访问审计
*/
public static final String ROLE_SESSION_NAME = "test";
/**
* 阿里云EndPoint
*/
public static final String END_POINT = "http://oss-cn-hangzhou.aliyuncs.com/";
/**
* 上传的Bucket
*/
public static final String bucketName = "bucketName";
/**
* RAM里的用户 AK,不可用全局AK
*/
public static final String accessKeyId = "aa";
/**
* RAM里的用户 SK,不可用全局SK
*/
public static final String accessKeySecret = "aabb";
/**
* 生成的ak sk 过期时间
*/
public static final Long expirationTime = 900L;
public static void main(String[] args) throws Exception
Credentials credentials = createSTSForPutObject(bucketName, ROLE_ARN, accessKeyId, accessKeySecret, expirationTime);
System.out.println(JSON.toJSONString(credentials));
OSS ossClient = new OSSClientBuilder().build(END_POINT, credentials.getAccessKeyId(), credentials.getAccessKeySecret(), credentials.getSecurityToken());
ossClient.putObject(bucketName, "1.mp4", new File("C:\\\\Users\\\\Administrator\\\\Videos\\\\朝天门.mp4"));
/**
* 创建上传临时账号
*
* @param bucketName
* @param roleArn 需要授权的角色名称
* @param accessKeyId 账号
* @param accessKeySecret 密码
* @param expirationTime 过期时间,单位为秒
* @return
*/
以上是关于阿里云OSS使用RAM生成STS分片上传大文件Demo的主要内容,如果未能解决你的问题,请参考以下文章