如何简单地在浏览器中使用阿里云的文件上传功能?
来源:互联网 发布:数据库表重命名as语句 编辑:程序博客网 时间:2024/05/17 02:52
明哥从办公室里发出一声怒吼:“这阿里云OSS服务的上传功能也太难用了,没有批量重命名功能,难道这几百个文件要我一个个手动重命名??!!”然后我和明哥就花了半天时间研究了下阿里云 SDK for JavaScript,顺利把文件上传功能集成到咱们的网站里了。
首先明确这次的需求:
- 能在后台进行文件的上传(单个文件大概在20M左右)
- 自动根据传入的ID和文件夹名对文件进行重命名
- 智能识别文件的后缀名,减少传错的可能性
- 显示上传进度且对上传的结果进行提示
接着去看一看阿里开放云存储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;})();
- 如何简单地在浏览器中使用阿里云的文件上传功能?
- VS2010中使用NeatUpload实现简单的文件上传功能
- 如何简单地找回保存在浏览器里的密码
- 在thinkphp中使用阿里云OSS自定义驱动上传文件
- 怎么简便地去掉html中难看的文件上传按钮并实现图片预览功能?
- 在struts2中上传图片 浏览器解析文件的不同类型
- 使用Html5的WebSocket在浏览器上传文件
- 使用Html5的WebSocket在浏览器上传文件
- 使用Html5的WebSocket在浏览器上传文件
- Jsp中如何使用Ckeditor富文本编译器以及实现上传文件的功能
- 在Java中简单地使用Access
- 如何在jsp中调用浏览器的打印功能
- 记录访客的(ip,浏览器,ip归属地,操作系统代码)并记录在文件中
- 如何在Symbian中使用Http上传大文件
- 如何在Symbian中使用Http上传大文件(转帖)
- 如何在 Laravel 中使用阿里云 OSS
- 如何在 Laravel 中使用阿里云 OSS
- 如何在 Laravel 中使用阿里云 OSS
- 内存分配与处理函数
- 初识软考之Java环境配置
- MQTT协议简记
- jquery datatable 参数
- JVM内存结构解析(一)
- 如何简单地在浏览器中使用阿里云的文件上传功能?
- Android 权限配置
- OpenGl Mip贴图
- NotificationListenerService 监听应用程序消息
- Serializable 作用
- FPGA编程的四种思想
- 【J2SE视频】-JDK安装
- android 一个apk调用另一个apk
- 欢迎使用CSDN-markdown编辑器