如何上传文件到腾讯云COS及踩坑?

4,445 阅读2分钟

之前公司使用的百度云BOS上传,当时也查了不少资料,但是没整理发布o(╥﹏╥)o,由于不知名原因,现在要换成COS,于是又开始了一波查文档敲代码的过程

一、COS官方文档

1. 安装&引入
npm i cos-js-sdk-v5 --save

import COS from 'cos-js-sdk-v5';
2. 使用
<input type="file" value="选择文件" ref="fileUpload" @change="uploadFile" />
getCos() {
    this.cosClient = new COS({
        getAuthorization: (options, callback) => {
        // 异步获取临时密钥
          this.$fetch({
            url: '/xxx/api/getxxxkey',
            method: 'get',
          }).then((res) => {
            if (res && res.errNo === 0) {
              const { data } = res;
              callback({
                TmpSecretId: data.tmpSecretId,
                TmpSecretKey: data.tmpSecretKey,
                XCosSecurityToken: data.sessionToken,
                StartTime: data.StartTime,
                ExpiredTime: data.ExpiredTime,
              });
            }
          }).catch(() => {
            this.loading = false;
          });
        },
    });
},
uploadFile(e) {
  const file = e.target.files[0];
  Promise
    .all([this.getCos()]) // 获取文件的md5
    .then((md5) => {
      const fileName = md5[0];
      const name = file.name.replace(/.*\.(.*)|(.*)/, (all, ext) => `${fileName}.${ext || all}`);
      const date = this.dateStr(); // 获取上传日期,例:20200108
      this.bucketPath = `xaj/test/${date}/${name}`; // Key: 对象键(Object 的名称),对象在存储桶中的唯一标识
      this.putObject([this.bucketPath, file]);
    });
},
putObject([key, file]) {
    // 简单上传文件
    this.cosClient.putObject({
        Bucket: 'test-124545', // 存储桶名称,必须;Bucket 格式:test-1250000000
        Region: 'ap-beijing', // 存储桶所在地域, 必须
        Key: key, /* 必须 */
        StorageClass: 'STANDARD',
        Body: file, // 上传文件对象
    }, (err, data) => {
        if (err) {
          this.$message.error(err);
        } else {
          this.$message.success('文件上传成功~');
          // 获取url
          const url = this.cosClient.getObjectUrl({
            Bucket: 'test-124545',
            Region: 'ap-beijing',
            Key: key,
          });
          console.log(url); // 有效可访问url生成
        }
    });
},



官方文档中简单文件上传快速入口, 官方文档中获取签名url快速入口。

3. 临时密钥

由于密钥放在前端会显示 SecretId 和 SecretKey,我们把永久密钥过程放在后端,前端通过 ajax 向后端获取一个临时密钥,正式部署时请再后端加一层您网站本身的权限检验。

// 初始化实例
var cos = new COS({
    getAuthorization: function (options, callback) {
        // 异步获取临时密钥
        $.get('http://example.com/server/sts.php', {
            bucket: options.Bucket,
            region: options.Region,
        }, function (data) {
            var credentials = data.credentials;
            callback({
                 TmpSecretId: credentials.tmpSecretId,
                 TmpSecretKey: credentials.tmpSecretKey,
                 XCosSecurityToken: credentials.sessionToken,
                 // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
                 StartTime: data.startTime, // 单位是秒
                 ExpiredTime: data.expiredTime
            });
        });
    }
});

callback释义:客户端请求COS,出于安全考虑使用的密钥要受到policy的约束,callback就是得到server端返回的 临时账号信息,包括

TmpSecretId: credentials.tmpSecretId,
TmpSecretKey: credentials.tmpSecretKey,
XCosSecurityToken: credentials.sessionToken,
StartTime: data.startTime, // 时间戳,单位秒,如:1580000000
ExpiredTime: data.expiredTime,

客户端再用临时账号密钥和tokenCOS发起请求。

4. 踩坑解决

① 按照文档中的方法使用getAuthorization,并无法正常上传,会提示authorization error,是因为我在使用时没有给callbackStartTimeExpiredTime

② 上传成功后返回的链接无法正常打开,报错Cos Error Code: AccessDenied,后经过查资料,得知是后端生成临时密钥时,没给getObject权限,如下$config最后一行:

$config = [
    'url' => URL,
    'domain' => DOMAIN,
    'proxy' => '',
    'secretId' => $conf['secret_id'], // 固定密钥
    'secretKey' => $conf['secret_key'], // 固定密钥
    'bucket' => $bucket, // 换成你的 bucket
    'region' => $region, // 换成 bucket 所在园区
    'durationSeconds' => EXPIRE_TIME, // 密钥有效期
    'allowPrefix' => '*', // 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的目录,例子:* 或者 a/* 或者 a.jpg
    // 密钥的权限列表。简单上传和分片需要以下的权限,
    'allowActions' => array (
        // 简单上传
        'name/cos:PutObject',
        'name/cos:PostObject',
        // 分片上传
        'name/cos:InitiateMultipartUpload',
        'name/cos:ListMultipartUploads',
        'name/cos:ListParts',
        'name/cos:UploadPart',
        'name/cos:CompleteMultipartUpload',
        // 下载
        'name/cos:GetObject',
    )
];
// 获取临时密钥,计算签名
$tempKeys = $this->sts->getTempKeys($config);

二、如何查看COS的SecretIdSecretKeyregionbucket

1. bucket/region

2. SecretId/SecretKey

点击【运API密钥】

【继续使用】

第一次进入时要点击【新建密钥】生成密钥,即可查看。

三、上传文件所在位置

log

2020-03-19:更新临时密钥使用问题解决(踩坑)