上一篇讲了如何通过 Web 直传文件到 COS,在其基础上介绍上传后如何下载文件

后端 STS 服务

首先后端的 STS 服务需要改造一下,增加查询下载 URL 的权限

{
    Action: []string{
        // 下载操作
        "name/cos:GetObject",
    },
    Effect: "allow",
    Resource: []string{
        "qcs::cos:ap-guangzhou:uid/" + appId + ":" + bucket + "/*",
    },
    Condition: map[string]map[string]interface{}{},
},

其他权限列表请可以看:

前端 Demo 改造

参考Javascript SDK,上传后通过 SDK 得到访问 URL,可以在页面展示或者下载

<template>
  <div>
    <div>
      <input type="file" @change="uploadImage" ref="imageInput" />
      <button @click="submitImage">Upload Image</button>
      <button v-if="imageUrl" @click="downloadImage">Download Image</button>
    </div>
    <div>
      <img v-if="imageUrl" :src="imageUrl" alt="Description of image ">
    </div>
  </div>
</template>
  
<script>
import COS from 'cos-js-sdk-v5';
const bucket = ${bucket};
const region = ${region};

export default {
  data() {
    return {
      imageFile: null,
      cos: null,
      imageUrl: null,
      imageKey: null,
      tmpSecretId: "",
      tmpSecretKey: "",
      sessionToken: "",
    };
  },
  methods: {
    uploadImage(event) {
      this.imageFile = event.target.files && event.target.files[0];
    },
    submitImage() {
      if (!this.imageFile) {
        alert("Please choose an image to upload.");
        return;
      }
      this.initCOS();
      this.uploadToCOS();
    },
    initCOS() {
      this.cos = new COS({
        getAuthorization: function (options, callback) {
          const url = 'http://${host}:8080/credentials'
          const xhr = new XMLHttpRequest()
          let data = null
          let credentials = null
          xhr.open('GET', url, true)
          xhr.onload = function (e) {
            try {
              data = JSON.parse(e.target.responseText);
              credentials = data.credentials;
            } catch (e) {
              console.log(e)
            }
            if (!data || !credentials) {
              return console.error('credentials invalid:\n' + JSON.stringify(data, null, 2))
            }
            callback({
              TmpSecretId: credentials.tmpSecretId,
              TmpSecretKey: credentials.tmpSecretKey,
              SecurityToken: credentials.sessionToken,
              StartTime: data.startTime, // 时间戳,单位秒,如:1580000000
              ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000000
            })
          }
          xhr.send();
        }
      })
    },
    uploadToCOS() {
      const key = `test/${Date.now()}_${this.imageFile.name}`;
      this.cos.uploadFile(
        {
          Bucket: bucket,
          Region: region,
          Key: key,
          StorageClass: "STANDARD",
          Body: this.imageFile,
        },
        (err) => {
          if (err) {
            console.error("Error uploading image:", err);
            alert("Error uploading image.");
          } else {
            this.imageKey = key;
            this.getImageUrl()
            alert("Image uploaded successfully.");
            this.$refs.imageInput.value = null;
            this.imageFile = null;
          }
        }
      );
    },

    getImageUrl() {
      let that = this
      this.cos.getObjectUrl({
        Bucket: bucket,
        Region: region,
        Key: this.imageKey,
      }, function (err, data) {
        if (err) return console.log(err);
        /* 通过指定 response-content-disposition=attachment 实现强制下载 */
        const downloadUrl = data.Url + (data.Url.indexOf('?') > -1 ? '&' : '?') + 'response-content-disposition=attachment';
        /* 可拼接 filename 来实现下载时重命名 */
        /* downloadUrl += ';filename=myname'; */
        // (推荐使用 window.open()方式)这里是新窗口打开 url,如果需要在当前窗口打开,可以使用隐藏的 iframe 下载,或使用 a 标签 download 属性协助下载
        that.imageUrl = downloadUrl
        console.log("Image uploaded successfully. URL:", that.imageUrl);
      })
    },
    downloadImage() {
      const link = document.createElement("a");
      link.href = this.imageUrl;
      link.download = this.imageUrl.split("/").pop();
      link.click();
    },
  },
};
</script>