如何简单地在浏览器中使用阿里云的文件上传功能?

来源:互联网 发布:数据库表重命名as语句 编辑:程序博客网 时间:2024/05/17 02:52

明哥从办公室里发出一声怒吼:“这阿里云OSS服务的上传功能也太难用了,没有批量重命名功能,难道这几百个文件要我一个个手动重命名??!!”然后我和明哥就花了半天时间研究了下阿里云 SDK for JavaScript,顺利把文件上传功能集成到咱们的网站里了。
首先明确这次的需求:

  1. 能在后台进行文件的上传(单个文件大概在20M左右)
  2. 自动根据传入的ID和文件夹名对文件进行重命名
  3. 智能识别文件的后缀名,减少传错的可能性
  4. 显示上传进度且对上传的结果进行提示

接着去看一看阿里开放云存储OSS的介绍和基础概念 在申请了服务之后,阿里会提供一个bucket(可以理解为在阿里云上你上传的文件所在的文件夹名),同时拥有有对应的 Access Key ID & Access Key Secret (用于加密),阿里云把每一个文件当做Object对待,我们在浏览器端使用POST方式来上传文件,对于用Node.js上传文件,阿里在GitHub上提供了一个例子,基本上参考这个例子就可以写出完整的上传功能了。地址如下:https://github.com/aliyun-UED
首先我们要用npm安装阿里云SDK:

npm install aliyun-sdk

接下来需要添加aliyun-sdk.min和oss-js-upload这两个js文件,前者能在浏览器端调用aliyun sdk,后者对文件上传进行了一系列的封装,在这里我们对oss-js-upload.js文件进行了改造,使其增加了显示上传进度的功能,这是本文的重点所在,具体改动详见源代码文件,一开始根本不知道如何显示进度,但是在调试GitHub上阿里云团队提供的例子时,发现后台会打印出诸如 “Completed part 1”、”Completed part 2” 的信息,联系到Http POST请求的特征(一次最多传2M左右的文件),所以说在oss-js-upload中就是使用Mutilpart方法进行上传的,那么我们只要获取到各个块的上传进度,除以总的块数,不就可以显示上传进度了么?关键的思路就在这里!想通了这一点,那么接下来就好办多了!

最后贴上源代码供大家参考,重点需要注意的地方我已经加了标注,如果再有什么不懂的可以在评论区给我留言。

upload.js

/** * Created by Young on 2015/8/28. * wang645788@gmail.com *///阿里云提供功能的上传类var ossUpload = new OssUpload({  bucket: 'keju-video',  // 选择杭州的 oss 实例所在地区选择填入,这里选的是  endpoint: 'http://oss-cn-hangzhou.aliyuncs.com',  // 如果文件大于 chunkSize 则分块上传, chunkSize 不能小于 100KB 即 102400  chunkSize: 1048576,  // 分块上传的并发数  concurrency: 5,  aliyunCredential: {    "accessKeyId": "在阿里云申请的accessKeyId",    "secretAccessKey": "在阿里云申请的secretAccessKey"  },  stsToken: null});var videoMp4;var folderName;var lessonId = "将要传的文件的ID以某种方式传入即可"; //获取要上传视频的ID,便于填写文件名//检查视频文件的后缀名String.prototype.endsWith = function (suffix) {  return !!this.match(suffix + "$");};var uploadVideo = function (type, file, fnProgress, fnSuccess, fnFail) {  var video = file;  var progress = 0;  ossUpload.upload({    // 必传参数, 需要上传的文件对象    file: video,    // 必传参数, 文件上传到 oss 后的名称, 包含路径    key: type + '/' + folderName + '/' + lessonId + '.' + type,    // 上传失败后重试次数    maxRetry: 3,    headers: {      'CacheControl': 'public',      'Expires': '',      'ContentEncoding': '',      'ContentDisposition': '',      // oss 支持的 header, 目前仅支持 x-oss-server-side-encryption      'ServerSideEncryption': ''    },    // 文件上传失败后调用, 可选参数    onerror: function (evt) {      console.log("error");      console.log(evt);      fnFail();    },    // 文件上传时的进度,每完成一片更新一次    onprogress: function (loaded, total) {      console.log(loaded, total, (loaded / total * 100).toFixed(1) + "%");      progress = (loaded / total * 100).toFixed(1) + "%";      fnProgress(progress);    },    // 文件上传成功调用, 可选参数    oncomplete: function (res) {      console.log("success");      console.log(res);      fnSuccess();    }  });};//选择上传的MP4文件$("#btnSelectMp4").click(function () {  $("#mp4File")    .trigger("click")    .change(function (evt) {      //得到上传的文件对象      videoMp4 = evt.target.files[0];      folderName = $("#inputFolderName").val();      if (videoMp4.name.endsWith('mp4')) {        $("#btnUploadMp4").show();      } else {        return $("#tipNotMp4").show();      }    });});//点击开始上传Mp4文件$("#btnUploadMp4").click(function () {  var btnUploadMp4 = $("#btnUploadMp4");  btnUploadMp4.prop('disabled', true);  btnUploadMp4.text("正在上传");  uploadVideo('mp4', videoMp4, function (progress) {    console.log("the progress is " + progress);    btnUploadMp4.text(progress);  }, function () {    btnUploadMp4.prop('disabled', false);    btnUploadMp4.hide();    btnUploadMp4.text('上传.mp4文件');    $("#uploadMp4Succeed").show();    $("#btnSelectMp4").show();    $('#mp4Address').val('');    $("#mp4File").replaceWith($("#mp4File").val('').clone(true));  }, function () {      //上传如果失败,则再次显示按钮让用户重新上传    btnUploadMp4.prop('disabled', false);    btnUploadMp4.text('上传.mp4文件');    btnUploadMp4.hide();    $("#uploadMp4Failed").show();    $("#btnSelectMp4").show();    $('#mp4Address').val('');    $("#mp4File").replaceWith($("#mp4File").val('').clone(true));  });});

oss-js-upload.js

'use strict';(function () {  var detectIEVersion = function () {    var v = 4,      div = document.createElement('div'),      all = div.getElementsByTagName('i');    while (      div.innerHTML = '<!--[if gt IE ' + v + ']><i></i><![endif]-->',        all[0]      ) {      v++;    }    return v > 4 ? v : false;  };  var _extend = function (dst, src) {    for (var i in src) {      if (Object.prototype.hasOwnProperty.call(src, i) && src[i]) {        dst[i] = src[i];      }    }  };  function OssUpload(config) {    if (!config) {      // console.log('需要 config');      return;    }    this._config = {      chunkSize: 1048576    // 1MB    };    if (this._config.chunkSize && this._config.chunkSize < 102400) {      // console.log('chunkSize 不能小于 100KB');      return;    }    _extend(this._config, config);    if (!this._config.aliyunCredential && !this._config.stsToken) {      // console.log('需要 stsToken');      return;    }    if (!this._config.endpoint) {      // console.log('需要 endpoint');      return;    }    var ALY = window.ALY;    if (this._config.stsToken) {      this.oss = new ALY.OSS({        accessKeyId: this._config.stsToken.Credentials.AccessKeyId,        secretAccessKey: this._config.stsToken.Credentials.AccessKeySecret,        securityToken: this._config.stsToken.Credentials.SecurityToken,        endpoint: this._config.endpoint,        apiVersion: '2013-10-15'      });    }    else {      this.oss = new ALY.OSS({        accessKeyId: this._config.aliyunCredential.accessKeyId,        secretAccessKey: this._config.aliyunCredential.secretAccessKey,        endpoint: this._config.endpoint,        apiVersion: '2013-10-15'      });    }    var arr = this._config.endpoint.split('://');    if (arr.length < 2) {      // console.log('endpoint 格式错误');      return;    }    this._config.endpoint = {      protocol: arr[0],      host: arr[1]    }  }  OssUpload.prototype.upload = function (options) {    if (!options) {      if (typeof options.onerror == 'function') {        options.onerror('需要 options');      }      return;    }    if (!options.file) {      if (typeof options.onerror == 'function') {        options.onerror('需要 file');      }      return;    }    var file = options.file;    if (!options.key) {      if (typeof options.onerror == 'function') {        options.onerror('需要 key');      }      return;    }    // 去掉 key 开头的 /    options.key.replace(new RegExp("^\/"), '');    var self = this;    var readFile = function (callback) {      var result = {        chunksHash: {},        chunks: []      };      var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;      var chunkSize = self._config.chunkSize;      var chunksNum = Math.ceil(file.size / chunkSize);      var currentChunk = 0;      var frOnload = function (e) {        result.chunks[currentChunk] = e.target.result;        currentChunk++;        if (currentChunk < chunksNum) {          loadNext();        }        else {          result.file_size = file.size;          callback(null, result);        }      };      var frOnerror = function () {        console.error("读取文件失败");        if (typeof options.onerror == 'function') {          options.onerror("读取文件失败");        }      };      function loadNext() {        var fileReader = new FileReader();        fileReader.onload = frOnload;        fileReader.onerror = frOnerror;        var start = currentChunk * chunkSize,          end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;        var blobPacket = blobSlice.call(file, start, end);        fileReader.readAsArrayBuffer(blobPacket);      }      loadNext();    };    var uploadSingle = function (result, callback) {      var params = {        Bucket: self._config.bucket,        Key: options.key,        Body: result.chunks[0],        ContentType: file.type || ''      };      _extend(params, options.headers);      self.oss.putObject(params, callback);    };    var uploadMultipart = function (result, callback) {      var maxUploadTries = options.maxRetry || 3;      var uploadId;      var loadedNum = 0;      var latestUploadNum = -1;      var concurrency = 0;      var multipartMap = {        Parts: []      };     ``` javascript         //这里使用arguments读取传入的onProgres函数并回调      if(3===arguments.length){        var fnProgress = arguments[2];      }     ```      var init = function () {        var params = {          Bucket: self._config.bucket,          Key: options.key,          ContentType: file.type || ''        };        _extend(params, options.headers);        self.oss.createMultipartUpload(params,          function (mpErr, res) {            if (mpErr) {              // console.log('Error!', mpErr);              callback(mpErr);              return;            }            // console.log("Got upload ID", res.UploadId);            uploadId = res.UploadId;            uploadPart(0);          });      };      var uploadPart = function (partNum) {        if(partNum >= result.chunks.length) {          return;        }        concurrency++;        if(latestUploadNum < partNum) {          latestUploadNum = partNum;        }        if(concurrency < self._config.concurrency && (partNum < (result.chunks.length - 1))) {          uploadPart(partNum + 1);        }        var partParams = {          Body: result.chunks[partNum],          Bucket: self._config.bucket,          Key: options.key,          PartNumber: String(partNum + 1),          UploadId: uploadId        };        var tryNum = 1;        var doUpload = function () {          self.oss.uploadPart(partParams, function (multiErr, mData) {            if (multiErr) {              // console.log('multiErr, upload part error:', multiErr);              if (tryNum > maxUploadTries) {                console.log('上传分片失败: #', partParams.PartNumber);                callback(multiErr);              }              else {                console.log('重新上传分片: #', partParams.PartNumber);                tryNum++;                doUpload();              }              return;            }            // console.log(mData);            concurrency--;            multipartMap.Parts[partNum] = {              ETag: mData.ETag,              PartNumber: partNum + 1            };            console.log("Completed part", partNum + 1);            //console.log('mData', mData);            loadedNum++;            ``` JavaScript            //回调upload.js文件中写的onprogress函数,显示进度            if("function" === typeof fnProgress){              fnProgress(loadedNum, result.chunks.length);            }            ```            if (loadedNum == result.chunks.length) {              complete();            }            else {              uploadPart(latestUploadNum + 1);            }          });        };        doUpload();      };      var complete = function () {        // console.log("Completing upload...");        var doneParams = {          Bucket: self._config.bucket,          Key: options.key,          CompleteMultipartUpload: multipartMap,          UploadId: uploadId        };        self.oss.completeMultipartUpload(doneParams, callback);      };      init();    };    readFile(function (err, result) {      var callback = function (err, res) {        if (err) {          if (typeof options.onerror == 'function') {            options.onerror(err);          }          return;        }        if (typeof options.oncomplete == 'function') {          options.oncomplete(res);        }      };      if (result.chunks.length == 1) {        uploadSingle(result, callback)      }      else {      //若文件大于2MB,使用分块上传,显示进度,若小于2MB,则不显示进度直接上传        if('function' === typeof options.onprogress){          uploadMultipart(result, callback, options.onprogress);        } else {          uploadMultipart(result, callback);        }      }    });  };  window.OssUpload = OssUpload;})();
0 0
原创粉丝点击