问题描述:通用上传方法都是有前端上传至服务器,再由服务器转存至对象存储。这种方法在小文件图片以及音频传输速度较为可以,但针对于大文件上传时,由于收服务器带块影响速度极慢,后使用对象存储分片上传虽然解决了服务器至oss的时间,但前端值服务器的传输过程还是收带宽影响;通常阿里云ECS带宽5M计算的话100MB*8=800Mb/5Mbps=160秒,所以100MB大小的文件如果是满带宽上传到服务器要160秒,所以速度相当慢。
解决方式:使用后端签名小程序直传方式跳过服务器转存。操作方式如下。阿里云OSS文档 https://help.aliyun.com/document_detail/92883.html?spm=a2c4g.11186623.6.1747.61423529zxUJcF
JAVA后端签名
- 引入Maven依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.8.0</version>
</dependency>
- 接受参数
Name | Type | Note |
---|---|---|
dir | String | 存储的相对路径。需要计算进policy,因此前端发起putObject请求中key参数的相应字段也要保持一致 |
- 返回参数(类型 JSONObject)
Name | Type | Note |
---|---|---|
accessId | String | |
policy | String | Base64编码 |
signature | String |
- 签名参考代码
@GetMapping("/getSign")
@ResponseBody
protected AjaxResult getSignature(String dir){
String endpoint = "";
String accessId = "";
String accessKey = "";
try {
OSSClient ossClient = new OSSClient(endpoint,accessId,accessKey);
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 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);//根据参数dir计算的policy,如果和前端uploadfile中参数key的相应字段不一致的话是会报错的
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes();
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
ossClient.shutdown();//业务完成一定要调用shutdown
Map<String, Object> map = new HashMap<String, Object>();
map.put("accessId",accessId);
map.put("policy", encodedPolicy);
map.put("signature", postSignature);
return AjaxResult.success(map);
} catch (Exception e) {
//Assert.fail(e.getMessage());
}
return null;
}
前端部分(微信小程序)
注意:wx.uploadFile中请求头header需要配置一个"Content-Type": “multipart/form-data”,不然可能会出现formData带不上的情况
formData中的key参数,是由dir和name组成的,需要和policy中的一致,不然会报policy无效的错误
uploadTest:function(){
wx.chooseImage({
count: 1,
success: function(res) {
//选择图片成功回调
wx.showLoading({
title: '上传中',
mask: true
})
var tempPath=res.tempFilePaths[0]
var dir='punchImg/'
//发起后端请求签名
wx.request({
url: '<Your signature server>',
data:{dir:dir},
success:function(res){
var l=tempPath.length
var newName = Date.parse(new Date()) + tempPath.substring(l-10)
//发起putObject请求,直传OSS
wx.uploadFile({
url: 'Your oss url',
filePath: tempPath,
name: 'file',
header: {
"Content-Type": "multipart/form-data"
},
formData:{
name: newName,
key:dir+newName,
policy: res.data.policy,
OSSAccessKeyId: res.data.accessId,
success_action_status: '200',
signature: res.data.signature
},
success:function(res){
wx.hideLoading()
console.log(res)
}
})
}
})
},
})
}