微信小程序上传单张图片至阿里云OSS(java后端签名+前端直传)
I.OSS基础:
II.JAVA后端签名部分
生产环境下考虑到安全因素,通常不会在前端直接完成签名,因此我把敏感信息和签名的业务流程都放在后端。
- Maven引入jar包
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.8.0</version>
</dependency>
- 后端存储信息
Name | Type | Src |
---|---|---|
accessId | String | OSS控制台 |
accessKey | String | OSS控制台 |
endpoint | String | OSS控制台 |
- 接收参数
Name | Type | Note |
---|---|---|
dir | String | 存储的相对路径。需要计算进policy,因此前端发起putObject请求中key参数的相应字段也要保持一致 |
- 返回JSONObject
Name | Type | Note |
---|---|---|
accessId | String | |
policy | String | Base64编码 |
signature | String |
- 参考代码
通过参考官方给的JAVA最佳实践,因为只需要计算policy和signature,所以阉割修改了一下
@RestController
protected JSONObject getSignature(String dir){
String endpoint = "<Your endpoint>";
String accessId = "<Your accessId>";
String accessKey = "<Your 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 new JSONObject(map);
} catch (Exception e) {
//Assert.fail(e.getMessage());
}
return null;
}
III.前端部分(微信小程序)
实际开发的时候参考过阿里云官方给的最佳实践,但是感觉并不是特别符合我的需求,因此进行了定制开发。
需要注意的是
- wx.chooseImage返回的是带微信平台经过计算的文件名的路径,并且不能直接获取该文件名。因此我直接弃用临时文件名,用时间戳加上临时文件名的后10位作为存入OSS的文件名,这样既可以避免重名,又可以获取文件格式(后4位),文件名中的时间戳亦可以另作他用。
- 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)
}
})
}
})
},
})
}