Vue上传文件到腾讯云cos桶

3,287 阅读3分钟

1.何时需要从前端直接上传文件到腾讯云cos桶

大多数情况下文件上传是将文件传给后端,后端再处理上传至腾讯云的逻辑。

但也有一些情况,比如上传1000个用户同时上传,上传了1000个文件给服务器,由于上传文件耗时相对较长,就会造成堵塞。这时,就需要从前端直接上传文件到腾讯云的cos桶。这样1000个用户都通过自己的浏览器调用不同的腾讯云上传接口,就可以保证性能啦~

2.具体操作

腾讯云cos官方文档

本方法适用于需要加密程度较高的上传功能————通过前端调用后端接口,获取临时密钥,前台再用临时密钥上传至腾讯云cos桶。如果对加密程度要求不高,可以使用永久密钥.

第一步:安装 SDK

通过 npm 安装环境 SDK: npm 地址


npm i cos-nodejs-sdk-v5 --save

第二步:新建uploadCos.js。

这里是为了让代码结构规范化,如果追求不高,可以写在页面文件里。

// 腾讯云对象存储
import COS from 'cos-js-sdk-v5'
// getCosSign是向后台请求的接口,传参依照情况而定。一般后台会返回密钥等相关信息
import {getCosSign} from '@kms/api/monthReportManagement/index';

import {Message} from 'element-ui'

var config = {
  Bucket: '',
  Region: '',
  Baseurl: '',
  Key:''
};
export default function upload(file, callback) {
  // let fileUrl = ''
  getCosSign({
        fileName: file.name
  }).then(response => { // 后台接口返回 密钥相关信息
    if (response.success) {
      const resData = response.data
      const credentials = resData.credentials;
         config.Bucket = resData.bucket;
         config.Region = resData.region;
      config.Baseurl = resData.baseurl;
      config.Key = resData.key;
    let uploadFileName = Date.parse(new Date())
    var cos = new COS({
      getAuthorization: function (options, callback) {
        callback({
          TmpSecretId: credentials.tmpSecretId,
          TmpSecretKey: credentials.tmpSecretKey,
          XCosSecurityToken: credentials.sessionToken,
          StartTime: resData.startTime,
          ExpiredTime: resData.expiredTime,
          expiration: resData.expiration,
          requestId: resData.requestId
        })
      }
    })
    cos.putObject({// 此处用了最简单的上传函数,此外,腾讯云还支持分片上传函数等等。
        Bucket: config.Bucket, // 存储桶名称
        Region: config.Region, // 地区
        Key: config.Key, // 图片名称
        StorageClass: 'STANDARD',
        Body: file, // 上传文件对象
        onHashProgress: function (progressData) {
          console.log('校验中', JSON.stringify(progressData));
        },
        onProgress: function (progressData) {
          console.log('上传中', JSON.stringify(progressData));
      },
        
    },
      
      function (err, data) {// 此处的两个传参是腾讯云返回的,data与上面的data不一样。直接照着写就可以。
      // 这里的data如果是个带有Location等的对象,则说明上传成功。
        if (err) {
          Message({
            message: '文件上传失败,请重新上传',
            type: 'error',
          })
          // this.$message.error('文件上传失败,请重新上传')
        } else {
          let fileUrl = data.Location
          callback(fileUrl)
        }
      }
    )}
   
  })
}

第三步:在页面文件里引入upload.js文件,并写入el-upload

简化版el-upload:

.vue文件html部分:

  <el-upload
        ref="upload"
        :action="upload_url"
        :before-upload="beforeUpload"
        :file-list="fileList"
        
      >
        <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
      </el-upload>

.vue文件js部分

// data:
upload_url: '/api/major/report/upload',
fileList: [],
// methods

 beforeUpload(file) {
  uploadCos(file,res => {// 有返回值也就是res存在,就代表uploadCos.js文件里的             
         // --> callback(fileUrl)中的fileUrl存在,也就是说data有值,即上传成功。
        if(res){
          this.$message.success('上传成功')

        }
      })
      }

完整版el-upload:具体见element-ui的upload组件

.vue文件html部分:

  <el-upload
        ref="upload"
        :action="upload_url"
        :before-upload="beforeUpload"
        :file-list="fileList"
        :auto-upload="false"
        :limit="1"
        :on-exceed="handleExceed"
        :on-change="handleChange"
        :on-remove="handleRemove"
      >
        <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
        <el-button
          style="margin-left: 10px;"
          size="small"
          type="primary"
          @click="submitUpload(file)"
        >提交</el-button>
        <div slot="tip" class="el-upload__tip">只能上传pdf/pptx文件,且不超过10M</div>
      </el-upload>

.vue文件js部分

import uploadCos from '@kms/api/monthReportManagement/uploadCos'

// data:
      upload_url: '/api/major/report/upload',
      fileList: [],
      fileTypes: '.ppt,.pptx,.pdf',
      file: new File([''], '.txt', { type: 'text/plain' }),

 // methods:处理上传
    submitUpload() {
      if (this.file.name === '.txt') {
        this.$message({
          message: '未发现文件,请重新选择',
          type: 'warning',
        });
      } else {
        this.$confirm('请确认是否要上传?', '提示', {
          type: 'warning',
        }).then(() => {
          this.$refs.upload.submit();
        });
      }
    },
    // 文件改变更新文件状态
    handleChange(file) {
      this.file = file;
    },
    // 处理删除
    handleRemove(file, fileList) {
      this.file = new File([''], '.txt', { type: 'text/plain' });
    },

    // 限制上传
    handleExceed(files, fileList) {
      this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
    },
    // 上传前校验
    beforeUpload(file) {
      let _self = this;
      var testmsg = file.name.substring(file.name.lastIndexOf('.')).toLowerCase();
      if (_self.fileTypes.indexOf(testmsg) < 0) {
        _self.$message({
          message: testmsg + '类型文件不可上传,请重新选择',
          type: 'warning',
        });
        return false;
      }
      let fileTypesArr = _self.fileTypes.split(',');
      let mpTypes = ['.pdf', '.pptx'];
      // 判断文件是否符合要求
      if (fileTypesArr.indexOf(testmsg) < 0) {
        _self.$message({
          message: '上传文件只能是' + _self.fileTypes + '格式!',
          type: 'warning',
        });
        return false;
      } else if (mpTypes.indexOf(testmsg) < 0 || file.size / 1024 / 1024 > 10) {
        _self.$message({
          message: '上传文件过大,大小不可超过10M!',
          type: 'warning',
        });
        return false;
      } else if (new Date(this.deadTime + ' 23:59:59') < new Date()) {
        this.$message({
          type: 'warning',
          message: '超过上传时间,禁止上传',
        });
        return false;
      } else {
         uploadCos(file,res => {// 有返回值也就是res存在,就代表uploadCos.js文件里的             
         // --> callback(fileUrl)中的fileUrl存在,也就是说data有值,即上传成功。
        if(res){
          this.$message.success('上传成功')

        }
      })
        setTimeout(() => {
          this.$refs.upload.clearFiles();
        }, 1000);
      }
    },