如何簡單地在瀏覽器中使用阿里雲的檔案上傳功能?
前言
我開通了一個微信公共號“王和陽的航海日誌”,在上面記錄著自己的學習、思考、實踐和成長的過程,歡迎關注、交流和拍磚。
正文
明哥從辦公室裡發出一聲怒吼:“這阿里雲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.
* [email protected]
*/
//阿里雲提供功能的上傳類
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;
})();
相關推薦
如何簡單地在瀏覽器中使用阿里雲的檔案上傳功能?
前言 我開通了一個微信公共號“王和陽的航海日誌”,在上面記錄著自己的學習、思考、實踐和成長的過程,歡迎關注、交流和拍磚。 正文 明哥從辦公室裡發出一聲怒吼:“這阿里雲OSS服務的上傳功能也太難用了,沒有批量重新命名功能,難道這幾百個檔案要我一個個手
阿里雲伺服器 ---- 上傳下載檔案
1.xshell 使用xshell來操作服務非常方便,傳檔案也比較方便。 就是使用rz(上傳),sz(下載) 首先,伺服器要安裝了rz,sz 伺服器執行 yum install lrzsz 2.兩個伺服器之間 傳輸檔案 使用scp命令
阿里雲 javascript上傳檔案(圖片、視訊、壓縮包等檔案)到 物件儲存 OSS ,返回上傳檔案、圖片、音訊、視訊等URL路徑
目的:前端上傳檔案(圖片、視訊、音訊等)到阿里雲伺服器裡面,並且獲得上傳檔案的URL路徑 前提:首先要買一個阿里雲伺服器,自己百度不會; 第一步:登入阿里雲賬號,點選管理控制檯-->物件儲存 OSS 第二步:新建儲存空間(圖一、圖二) (圖一) (圖二
使用阿里雲OSS上傳下載專案檔案
1、登入阿里雲開通阿里雲OSS,根據官網說明進行操作獲取需要的配置引數 'id'=> '你的accessKeyId', 'key'=> '你的accessKeySecret', 'host' => 'oss-cn-beijing.aliyunc
tp5呼叫阿里雲oss上傳檔案
推薦使用composer方式 composer方式安裝SDK的步驟如下: 在專案的根目錄執行composer require aliyuncs/oss-sdk-php,或者在composer.j
怎麼簡便地去掉html中難看的檔案上傳按鈕並實現圖片預覽功能?
問題描述 通常的檔案上傳按鈕是這樣的: 選擇了檔案過後是這樣的: 很顯然,這樣的按鈕並不好看。 解決方法 用一個label標籤來裝載樣式,其for屬性指向type=file的inp
阿里雲OSS 上傳檔案 刪除檔案自封裝 —python
<pre name="code" class="python"># -*- coding: utf-8 -*- """ wrapper of oss2. """ import oss2 from PwLogging import PwLogging cl
SpringBoot基於阿里雲OSS上傳檔案
一:需求背景. Web系統開發中,檔案上傳是非常常見的功能,本來也沒啥好說的,就是通過IO流將檔案寫到另外一個地方,這個地方可以是 1. 專案的目錄中的某個資料夾. 2. 本地碟符的某個檔案下. 3. 雲服務OSS裡面.例如七牛雲,
阿里雲oss上傳本地檔案到伺服器例項
Java 專案開發中阿里雲 oss上傳本地到伺服器以及下載功能實現例項。 AliyunOSSUtil類: public class AliyunOSSUtil { /** * 該示例程式碼展示瞭如果在OSS中建立和刪除一個Bucket,以及如何上傳和下載一個檔案。 *
通過阿里雲的上傳路徑獲取EXCEL檔案進行資料讀取
通過需求,要對上傳的EXCEL檔案進行資料讀取併入庫。由於EXCEL是由前端直傳到阿里雲,所以只有一個上傳後的檔案路徑。對於先下載在讀取在刪除的方式覺得十分耗時且無用,所以試圖直接根據URL地址來讀取流,生成EXCEL物件並讀取資料。程式碼如下:public static v
阿里雲OSS上傳檔案工具類
/** * * * 阿里雲OSS上傳檔案工具 * * 支援普通檔案上傳,限制大小檔案上傳,限制大小圖片上傳 * * @version1.0 */public class AliyunOssUtil {private Logger logger =
阿里雲本地上傳資料夾內所有內容程式碼
public static void main(String[] args){ // Endpoint以杭州為例,其它Region請按實際情況填寫。 String endpoint = ""; // 阿里雲主賬號AccessKey擁有所有API的訪問許可權,風險很高。強烈建議您建立並使用RA
webupload上傳外掛中,單個檔案上傳處理
上傳外掛如何使用,我這裡就不多說了,網上大把教程。今天我要講的是如何限制上傳一個檔案,以及當檔案選擇錯誤是,再重新選擇檔案導致的問題。 預設給上傳外掛支援多檔案上傳,但是我們有很多需求是之上傳單個檔案,下面就來一起學習學習吧! 外掛html <div class="form-g
tp框架 阿里雲oss 上傳 ,刪除,判斷是不是存在
composer require aliyuncs/oss-sdk-php 配置檔案如下 'ALIOSS_CONFIG' => array( 'KEY_ID' => '', 'KEY_SECRET' => '',
Django - 實現簡單的檔案上傳功能
前端 <form action="" method="post" enctype="multipart/form-data"> {#<form action="" method="post" enctype="application/x-www-form-urlenc
Atitit 檔案上傳功能的實現 圖片 視訊 目錄 1. 上傳原理 1 1.1. http post編碼 multipart / form-data 1 1.2. 臨時檔案模式 最簡單 2 1.3
Atitit 檔案上傳功能的實現 圖片 視訊 目錄 1. 上傳原理 1 1.1. http post編碼 multipart / form-data 1 1.2. 臨時檔案模式 最簡單 2 1.3. 位元組陣列模式 簡單 2
ASP.NET簡單實現APP中使用者個人頭像上傳和裁剪
最近有個微信專案的使用者個人中心模組中,客戶要求使用者頭像不僅僅只是上傳圖片,還需要能對圖片進行裁剪。考慮到flash在IOS和Android上的相容性問題,於是想著能從js這塊入手,在網上發現了devotion博主寫的《適應各瀏覽器圖片裁剪無重新整理上傳js外掛》文章,從中受
Java專案整合阿里雲OSS上傳圖片
工具類: import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import org.slf4j.Lo
關於阿里雲oss上傳圖片之後會被旋轉90度的解決辦法
問題描述:正常的圖片前端上傳到oss成功之後的資源地址。在html上引用的時候被旋轉了90度oss資源地址直接在瀏覽器開啟就不會旋轉問題原因:某些手機拍攝出來的照片可能帶有旋轉引數(存放在照片exif資訊裡面)。而oss資源上傳之後會預設自適應方向所以在img標籤中圖片就被旋轉了90度。 解決辦法:阿里雲給
阿里雲oss上傳與下載
public class OSSClientUtil { //填入相應字串 private static String endpoint = ""; private static String accessKeyId = ""; private static Str