cos demo - zhouted/zhouted.github.io GitHub Wiki

COS是腾讯云提供的一种高扩展、低成本、可靠和安全存储海量文件的分布式存储服务,用户可通过网络随时存储和查看数据。

上传文件(前端)

上传页面需引入cos-js-sdk(下载:XML JavaScript SDK

<script src="tencent/cos-js-sdk-v5.min.js"></script>

使用html原生input file标签

<input type="file" id="file" name="file" multiple="multiple" @change="onSelectFile">

或外包一层label

<label>
  <input type="file" id="file" name="file" hidden multiple="multiple" @change="onSelectFile">
  <span>选择上传文件...</span>
</label>

上传处理用到的js(示例使用了vue)

new Vue({
  el: '#root',
  data: {
    cos: null,
    bucket: 'test-1301758919',
    region: 'ap-guangzhou',
    prefix: 'test/',//文件存放路径前缀
    uploading: false,
    uploads: [],//正在上传的对象
  },
  created: function () {
    this.init();
  },
  methods: {
    init: function () {
      var vue = this;
      vue.cos = $.newCos(vue.prefix);
    },
    onSelectFile: function ($event) {
      var vue = this;
      var files = $event.target.files;
      if (!files || !files.length) {
        return;
      }
      var ups = []; //upload promises
      vue.uploading = true;
      for (var i = 0; i < files.length; i++) { //循环上传所选文件
        var file = files[i];
        var upload = {
          cos: vue.cos,
          bucket: vue.bucket,
          region: vue.region,
          key: vue.prefix + file.name,
          file: file,
          uploading: true, //正在上传
          progress: { //存放进度
            uploaded: 0,
            percent: 0
          },
        }
        upload.onFinish = function (err, data) {
          vue.load();
          vue.uploads.splice(vue.uploads.indexOf(this), 1);
        }
        upload.onProgress = function (progress) {
          this.progress = progress;
          vue.uploads[vue.uploads.indexOf(this)] = this;
        };
        ups.push($.uploadFile(upload));
        vue.uploads.push(upload);
      }
      $.when.apply($, ups).then(function () {
        $event.target.value = '';
        vue.uploading = false;
      });
    },
    toggleTask: function (upload) { //暂停/继续上传任务
      if (upload.uploading) {
        upload.cos.pauseTask(upload.taskId);
      } else {
        upload.cos.restartTask(upload.taskId);
      }
      upload.uploading = !upload.uploading;
    },
  },
}

公共方法可以注入到jquery

//cos: new cos instance
$.newCOS = function(prefix){
  return new COS({
    FileParallelLimit: 10,
    getAuthorization: function(options, callback) {
      console.log(options);
      $.getJSON('/cos/sts', {prefix: prefix}, function(sts) {//后台提供的接口/cos/sts
        var credentials = sts && sts.credentials;
        if (!sts || !credentials) return console.error('credentials invalid');
        callback({
          TmpSecretId: credentials.tmpSecretId,
          TmpSecretKey: credentials.tmpSecretKey,
          XCosSecurityToken: credentials.sessionToken,
          StartTime: sts.startTime,
          ExpiredTime: sts.expiredTime,
        });
      });
    }
  });
}
//cos: upload file to cos
$.uploadCOS = function(upload){
  var deferred = $.Deferred();
  var uploadParam = {
      Bucket: upload.bucket||'test-1301758919',
      Region: upload.region||'ap-guangzhou',
      Key: upload.key||upload.file.name,
      Body: upload.file,
      onTaskReady: function(taskId) {
          upload.taskId = taskId;
      },
      onProgress: function (progressData) {
        upload.onProgress && upload.onProgress(progressData);
      },
  }
  upload.cos.sliceUploadFile(uploadParam, function(err, data) {
    //err && console.error(err);
    upload.onFinish && upload.onFinish(err, data);
    deferred.resolve(err, data);
  });
  return deferred.promise();
}

用一个table显示上传进度

<table class="table table-striped table-hover" v-show="uploads.length">
  <thead>
    <tr>
      <th>#</th><th>文件</th><th class="text-center">进度</th><th class="text-center">操作</th>
    </tr>
  </thead>
  <tbody>
    <tr v-for="(upload, idx) in uploads">
      <td>{{idx+1}}</td>
      <td>{{upload.file.name}}</td>
      <td class="text-center">
        <div class="progress" style="height:1.5rem;">
          <div class="progress-bar" role="progressbar" :style="{width: upload.progress.percent*100+'%'}" aria-valuemin="0" aria-valuemax="100">
            {{(upload.progress.percent*100).toFixed(0)}}%({{upload.progress.loaded}}/{{upload.file.size}})
          </div>
        </div> 
      </td>
      <td class="text-center">
        <button class="btn btn-link" @click="toggleTask(upload)">{{upload.uploading?'暂停':'继续'}}</button>
      </td>
    </tr>
  </tbody>
</table>

后端sts服务

pom.xml dependencies

<dependency>
  <groupId>com.qcloud</groupId>
  <artifactId>cos_api</artifactId>
  <version>5.6.19</version>
</dependency>
<dependency>
  <groupId>com.tencent.cloud</groupId>
  <artifactId>cos-sts-java</artifactId>
  <version>3.0.6</version>
</dependency>

CosController.java

import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.cloudbutterfly.demo.service.CosService;

@RestController
@RequestMapping("/cos")
public class CosController {
  @Autowired
  CosService cosService;
  
  @RequestMapping("/sts") //获取cos临时密钥sts接口
  String getSTS(String prefix) {
    JSONObject sts = cosService.getCredential(prefix);
    return sts.toString();
  }
  @RequestMapping("/dl") //下载接口
  void download(String key, HttpServletResponse response) throws IOException {
    String url = cosService.getCdnUrl(key);
    response.sendRedirect(url);
  }
}

CosService.java

import java.time.Instant;
import java.util.TreeMap;
import org.json.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import com.tencent.cloud.CosStsClient;

@Service
public class CosService {
  @Autowired CosConfig config;

  public JSONObject getCredential(String prefix) {
    TreeMap<String, Object> map = new TreeMap<String, Object>();
    try {
      map.put("SecretId", config.getSecretId());
      map.put("SecretKey", config.getSecretKey());
      map.put("durationSeconds", 1800);
      map.put("bucket", config.getBucket());
      map.put("region", config.getRegion());
      map.put("allowPrefix", prefix == null ? "*" : prefix + "*");
      String[] allowActions = new String[] {
          "name/cos:InitiateMultipartUpload", "name/cos:ListMultipartUploads", "name/cos:ListParts", "name/cos:UploadPart", "name/cos:CompleteMultipartUpload",// 分片上传 
        };
      map.put("allowActions", allowActions);

      JSONObject credential = CosStsClient.getCredential(map);
      return credential;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }
  //获取带鉴权的cdn访问url。如果不使用cdn则需调用cos.generatePresignedUrl(req)生成带签名的url
  public String getCdnUrl(String key) {
    long ts = Instant.now().getEpochSecond();
    String sign = DigestUtils.md5DigestAsHex(String.format("%s/%s%d", config.getCdnKey(), key, ts).getBytes());
    return String.format("%s%s?sign=%s&t=%d", config.getCdnAp(), key, sign, ts);
  }
}

CosConfig是配置类

public class CosConfig {
  private String bucket;//存储桶名
  private String region;//存储区域
  private String secretId;//访问密钥id
  private String secretKey;//访问密钥key
  private String cdnAp;//CDN接入点
  private String cdnKey;//CDN鉴权key
}
⚠️ **GitHub.com Fallback** ⚠️