问题描述:通用上传方法都是有前端上传至服务器,再由服务器转存至对象存储。这种方法在小文件图片以及音频传输速度较为可以,但针对于大文件上传时,由于收服务器带块影响速度极慢,后使用对象存储分片上传虽然解决了服务器至oss的时间,但前端值服务器的传输过程还是收带宽影响;通常阿里云ECS带宽5M计算的话100MB*8=800Mb/5Mbps=160秒,所以100MB大小的文件如果是满带宽上传到服务器要160秒,所以速度相当慢。
解决方式:使用后端签名小程序直传方式跳过服务器转存。操作方式如下。阿里云OSS文档 如何在微信小程序环境下将文件上传到OSS_对象存储(OSS)-阿里云帮助中心
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) } }) } }) }, }) }