Vue获取服务端签名web端直传OSS,各种报错The bucket POST must contain the specified ‘key‘.等解决办法

野性酷女 2023-01-19 03:24 99阅读 0赞

目录

    • 项目场景:
    • Vue获取服务端签名web端直传OSS
    • Java后台授权代码
  • 总结

项目场景:

文件上传阿里云OSS,通常情况下的上传方式是页面先文件上传到我们的后台服务器,我们的后台服务器在上传到OSS,这样的话一个文件的上传操作就相当于消耗了两份服务器带宽,
流程图如图所示:
在这里插入图片描述

而如果项目的文件或者图片上传业务比较大的话,显然这对服务器来说是一个不必要的开销。

当然,我们也有优化的解决办法,通过服务端给我们生成一个允许我们上传文件到OSS的签名,我们前端项目拿到这个签名去直接上传到OSS,这样就减少了额外的带宽开销,流程图如下所示:
在这里插入图片描述
具体的官方信息描述可以点击这里查看:
https://help.aliyun.com/document_detail/31927.html?spm=a2c4g.11186623.6.1744.17e03bd38ehYZz


Vue获取服务端签名web端直传OSS

  1. <template>
  2. <div class="test">
  3. <div>
  4. <input type="file" id="file" name="file" />
  5. <a @click="upload()" href="javascript:;">上传</a>
  6. </div>
  7. </div>
  8. </template>
  9. <script> export default { data(){ return { } }, mounted() { this.getOssToken(); }, methods: { //获取上传通行证 getOssToken(){ var _self = this; axios.get('/api/oss/getPolicy').then(function(res){ console.log(res); if(res.data.code == 200){ _self.aliyunOssToken = res.data.data; }else{ _self.$message.error(res.data.message); } }).catch(function(error){ console.log(error); }) }, upload(){ var _self = this; var getSuffix = function (fileName) { var pos = fileName.lastIndexOf("."); var suffix = ''; if (pos != -1) { suffix = fileName.substring(pos); } return suffix; } var file = $("#file").val(); if (file.length == 0) { alert("请选择文件"); } var filename = new Date().getTime() + getSuffix(file); var formData = new FormData(); //注意formData里append添加的键的大小写 formData.append('key', _self.aliyunOssToken.dir + filename); //存储在oss的文件路径 formData.append('OSSAccessKeyId', _self.aliyunOssToken.accessid); //accessKeyId formData.append('policy', _self.aliyunOssToken.policy); //policy formData.append('Signature', _self.aliyunOssToken.signature); //签名 //如果是base64文件,那么直接把base64字符串转成blob对象进行上传就可以了 formData.append("file", $("#file")[0].files[0]); formData.append('success_action_status', 200); //成功后返回的操作码 var url = _self.aliyunOssToken.host; var fileUrl = _self.aliyunOssToken.host +'/'+ _self.aliyunOssToken.dir + filename; $.ajax({ url: url, type: 'POST', data: formData, // async: false, cache: false, contentType: false, processData: false, success: function (data) { console.log(fileUrl); console.log(data); }, error: function (data) { console.log(data); } }); } } } </script>

这里需要注意的是:
如果你遇到了

  1. <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error>\n <Code>InvalidArgument</Code>\n <Message>The bucket POST must contain the specified 'key'. If it is specified, please check the order of the fields</Message>\n <RequestId>60950F076AD6D5

这种错误的话,那么可能,是你的key字段不存在,这里所有的字段名称一定要和官方文档给定的一致,否则就会报错,注意大小写。
如果不是的话,那么你可能就是遇到了跟我一样的错误,如图所示:

在这里插入图片描述

在这里插入图片描述
查阅官方文档后,官方文档给出的解释是这样的,点击查看:
如图所示:
在这里插入图片描述
如果还有其他错误,可对照官方文档一步步排查。

Java后台授权代码

这里我也给贴出来吧,省得你再去翻看官方文档了:
有点多,你就看你有用的就行:

  1. package cc.mrbird.febs.external.oss;
  2. import cc.mrbird.febs.common.entity.FebsResponse;
  3. import cc.mrbird.febs.common.exception.FebsException;
  4. import cc.mrbird.febs.common.utils.RandomUtil;
  5. import com.aliyun.oss.OSS;
  6. import com.aliyun.oss.OSSClientBuilder;
  7. import com.aliyun.oss.common.utils.BinaryUtil;
  8. import com.aliyun.oss.model.*;
  9. import lombok.Data;
  10. import org.joda.time.DateTime;
  11. import org.springframework.beans.factory.annotation.Value;
  12. import org.springframework.stereotype.Service;
  13. import org.springframework.web.multipart.MultipartFile;
  14. import javax.servlet.http.HttpServletResponse;
  15. import java.io.*;
  16. import java.net.URLEncoder;
  17. import java.nio.charset.StandardCharsets;
  18. import java.util.*;
  19. /** * @ Author 马超伟 * @ Date 2021-04-30 09:21 * @ Description: * @ Version: */
  20. @Data
  21. @Service
  22. public class OssFileUpload {
  23. @Value("${aliyun.oss.file.endpoint}")
  24. private String endpoint;
  25. @Value("${aliyun.oss.file.keyid}")
  26. private String accessKeyId;
  27. @Value("${aliyun.oss.file.keysecret}")
  28. private String accessKeySecret;
  29. @Value("${aliyun.oss.file.filehost}")
  30. private String fileHost;
  31. @Value("${aliyun.oss.file.bucketname}")
  32. private String bucketName;
  33. @Value("${aliyun.oss.file.callbackUrl}")
  34. private String callbackUrl;
  35. @Value("${aliyun.oss.file.baseDir}")
  36. private String dir;
  37. public OSS getOssClient() {
  38. OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
  39. ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
  40. return ossClient;
  41. }
  42. /** * @ Author: 马超伟 * @ Date: 2021/4/30 10:59 * @ Params: [file, basePath] * @ return: java.lang.String * @ Description: 文件上传 */
  43. public String upload(MultipartFile file, String basePath) {
  44. String uploadUrl;
  45. try {
  46. //判断oss实例是否存在:如果不存在则创建,如果存在则获取
  47. OSS ossClient = getOssClient();
  48. //获取上传文件流
  49. InputStream inputStream = file.getInputStream();
  50. //构建日期路径:avatar/2019/02/26/文件名
  51. String filePath = new DateTime().toString("yyyy/MM/dd");
  52. //文件名:uuid/原始文件名到后缀
  53. String original = file.getOriginalFilename();
  54. String fileName = RandomUtil.getLinkNo();
  55. String newName = fileName + "/" + original;
  56. String fileUrl = basePath + "/" + filePath + "/" + newName;
  57. //文件上传至阿里云
  58. ossClient.putObject(bucketName, fileUrl, inputStream);
  59. // 关闭OSSClient。
  60. ossClient.shutdown();
  61. //获取url地址
  62. uploadUrl = fileHost + "/" + fileUrl;
  63. } catch (IOException e) {
  64. throw new FebsException("文件上传异常!");
  65. }
  66. return uploadUrl;
  67. }
  68. /** * @return List<String> 文件路径和大小集合 * @ Param ossClient oss客户端 * @ Param bucketName bucket名称 * @Title: queryAllObject * @ Description: 查询某个bucket里面的所有文件 */
  69. public List<String> queryAllObject() {
  70. List<String> results = new ArrayList<>();
  71. try {
  72. // ossClient.listObjects返回ObjectListing实例,包含此次listObject请求的返回结果。
  73. ObjectListing objectListing = getOssClient().listObjects(bucketName);
  74. // objectListing.getObjectSummaries获取所有文件的描述信息。
  75. for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
  76. results.add(" - " + objectSummary.getKey() + " " + "(size = " + objectSummary.getSize() + ")");
  77. }
  78. } catch (Exception e) {
  79. e.printStackTrace();
  80. }
  81. return results;
  82. }
  83. /** * 从阿里云下载单个文件 * * @ Param objectName */
  84. public void download(String objectName, HttpServletResponse response) {
  85. BufferedInputStream input = null;
  86. OutputStream outputStream;
  87. OSSObject ossObject;
  88. try {
  89. objectName = objectName.replace(fileHost + "/", "");
  90. response.reset();
  91. response.setCharacterEncoding("utf-8");
  92. response.setContentType("application/x-msdownload");
  93. String substring = objectName.substring(objectName.lastIndexOf("/") + 1);
  94. response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(substring, "UTF-8"));
  95. // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
  96. ossObject = getOssClient().getObject(bucketName, objectName);
  97. input = new BufferedInputStream(ossObject.getObjectContent());
  98. byte[] buffBytes = new byte[1024];
  99. outputStream = response.getOutputStream();
  100. int read;
  101. while ((read = input.read(buffBytes)) != -1) {
  102. outputStream.write(buffBytes, 0, read);
  103. }
  104. input.close();
  105. ossObject.close();
  106. outputStream.close();
  107. } catch (IOException ex) {
  108. ex.printStackTrace();
  109. } finally {
  110. try {
  111. if (input != null) {
  112. input.close();
  113. }
  114. } catch (IOException e) {
  115. // e.printStackTrace();
  116. }
  117. }
  118. }
  119. public void downloadObject(String objectName) {
  120. // 创建OSSClient实例。
  121. OSS ossClient = getOssClient();
  122. // 下载Object到本地文件,并保存到指定的本地路径中。如果指定的本地文件存在会覆盖,不存在则新建。
  123. // 如果未指定本地路径,则下载后的文件默认保存到示例程序所属项目对应本地路径中。
  124. objectName = objectName.replace(fileHost + "/", "");
  125. ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File("D:\\localpath\\"+objectName));
  126. // 关闭OSSClient。
  127. ossClient.shutdown();
  128. }
  129. /** * 文件及文件夹的递归删除 * * @ Param file */
  130. private static void deleteFile(File file) {
  131. if (file.isDirectory()) {
  132. File[] files = file.listFiles();
  133. assert files != null;
  134. for (File f : files) {
  135. deleteFile(f);
  136. //将循环后的空文件夹删除
  137. if (f.exists()) {
  138. f.delete();
  139. }
  140. }
  141. } else {
  142. file.delete();
  143. }
  144. }
  145. /** * @ Author: 马超伟 * @ Date: 2021/5/7 18:16 * @ Params: [] * @ return: cc.mrbird.febs.common.entity.FebsResponse * @ Description: 前台获取文件上传签名授权 */
  146. public FebsResponse policy() {
  147. //https://gulimall-hello.oss-cn-beijing.aliyuncs.com/hahaha.jpg
  148. // callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
  149. // String callbackUrl = "http://88.88.88.88:8888";
  150. String filePath = new DateTime().toString("yyyy/MM/dd");
  151. String dir = "file/" + filePath; // 用户上传文件时指定的前缀。
  152. Map<String, String> respMap = null;
  153. try {
  154. long expireTime = 30;
  155. long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
  156. Date expiration = new Date(expireEndTime);
  157. PolicyConditions policyConds = new PolicyConditions();
  158. policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
  159. policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
  160. String postPolicy = getOssClient().generatePostPolicy(expiration, policyConds);
  161. byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
  162. String encodedPolicy = BinaryUtil.toBase64String(binaryData);
  163. String postSignature = getOssClient().calculatePostSignature(postPolicy);
  164. respMap = new LinkedHashMap<>();
  165. respMap.put("accessid", accessKeyId);
  166. respMap.put("policy", encodedPolicy);
  167. respMap.put("signature", postSignature);
  168. respMap.put("dir", dir);
  169. respMap.put("host", fileHost);
  170. respMap.put("expire", String.valueOf(expireEndTime / 1000));
  171. // respMap.put("expire", formatISO8601Date(expiration));
  172. } catch (Exception e) {
  173. // Assert.fail(e.getMessage());
  174. System.out.println(e.getMessage());
  175. }
  176. return new FebsResponse().success().put("data", respMap);
  177. }
  178. }

总结

遇到问题并不可怕,可怕的是找不出来问题在哪, 这种调用人家方法的,就按照人家的要求一步步走就行了,自己的任何‘**投机取巧、标新立异’**都是行不通的。

找到报错信息,去官方文档查阅‘常见问题’,解决起来就轻松多了。

发表评论

表情:
评论列表 (有 0 条评论,99人围观)

还没有评论,来说两句吧...

相关阅读