因為我的個人網站 restran.net 已經啟用,博客園的內容已經不再更新。請訪問我的個人網站獲取這篇文章的最新內容,七牛雲存儲的 Web 前端文件上傳
七牛是不錯的雲存儲產品,特別是有免費的配額可供使用,存點小文件或者博客的插圖什么的還是不錯的。以下介紹在自己的Web應用中上傳文件到七牛的方法。
基本思想
當我們想把本地的文件通過瀏覽器上傳到自己的七牛雲存儲空間上時,就有兩種思路
- 將文件直接上傳到服務端,再由服務端將文件傳輸至七牛
- 向服務端請求七牛的文件上傳token,然后將文件上傳至七牛(授權式上傳)
第1種方法較好解決,參考七牛的文檔即可,第2種方法效率較高,這里介紹第2種。
使用Javascript在Web前端上傳文件的方法,七牛官方給出了文檔和例子。核心內容在於這幾點:
- 指定上傳按鈕的ID
- 創建一個uploader
2.1 綁定上傳按鈕的ID
2.2 設置獲取上傳token的服務端url
<div id="btn-uploader">
<a id="pickfiles" href="javascript:void 0;">Upload File</a>
</div>
這里上傳按鈕的ID是pickfiles
uploader = Qiniu.uploader({
//...
});
設置uploader的參數
七牛的Javascript SDK使用到了Plupload,在初始化uploader
時,可以為其傳遞Plupload中給定的Option,而不僅局限於七牛例子中給出的。例如可以添加multi_selection
和filters
來限制上傳時,文件的選擇。
文件命名
當文件上傳至七牛雲存儲時,文件的命名顯得尤為重要,缺省情況下,七牛會使用上傳文件的名字命名,然而文件重名將難以避免,並且重名將導致無法上傳或覆蓋舊文件。為了解決這一問題,有三種方法
- 由qiniu自動生成唯一的文件名,在
uploader
中設置unique_names=true
- 由服務端生成文件名,在
uploader
中設置save_key=true
,並且在服務端返回token時,設置policy.saveKey
的值為所要保存的文件名。- Web 前端自定義文件名,
key
函數中設置文件名,缺點是文件名無法有效管理。
以下使用Python和Flask框架為例,介紹服務端生成文件名的方法。
import json
import qiniu.rs
@app.route("/qiniu-token/")
def qiniu_token():
policy = qiniu.rs.PutPolicy('your-bucket-name')
policy.saveKey = 'save_key'#設置上傳文件的文件名
uptoken = policy.token()
return json.dumps({'uptoken': uptoken})
服務端會返回如下格式的JSON,里面已包含了文件名
{
"uptoken": "0MLvWPnyya1WtPnXFy9KLyGHyFPNdZceomL..."
}
但是服務端仍無法獲悉本地文件的文件類型,因此無法給出恰當的文件名,雖然設置文件名時缺失擴展名,不影響文件的下載,但明顯不漂亮。
這時就需要先在本地先獲取文件擴展名后,再向服務端請求,由服務端安排一個文件名(服務端掌握所有文件的信息,可以方便文件的命名和管理)。
在uploader
的init
參數中,有一個key
參數,可以為其綁定函數來設置文件名。該函數啟用的前提是save_key
和unique_names
設為false
。
在key
對應的函數中使用ajax向服務端請求文件名,然后與文件的擴展名組合后就得到了恰當的文件名了。特別注意的是,這里的ajax調用用使用同步的方式,因為需要在該函數返回前就得到服務端回應的信息,如果使用異步的方式,函數都返回了,服務端還沒響應呢。
uploader = Qiniu.uploader({
//...
init: {
'Key': function(up, file) {
//當save_key和unique_names設為false時,該方法將被調用
var key = "";
$.ajax({
url: '/qiniu-token/get-key/',
type: 'GET',
async: false,//這里應設置為同步的方式
success: function(data) {
var ext = Qiniu.getFileExtension(file.name);
key = data + '.' + ext;
},
cache: false
});
return key;
}
//...
}
});
以下是uploader的詳細設置,其他完整的信息請參考七牛的例子,並加以改造。
uploader = Qiniu.uploader({
runtimes: 'html5,flash,html4',
browse_button: 'pickfiles',//上傳按鈕的ID
container: 'btn-uploader',//上傳按鈕的上級元素ID
drop_element: 'btn-uploader',
max_file_size: '100mb',//最大文件限制
flash_swf_url: '/static/js/plupload/Moxie.swf',
dragdrop: false,
chunk_size: '4mb',//分塊大小
uptoken_url: '/qiniu-token/',//設置請求qiniu-token的url
//Ajax請求upToken的Url,**強烈建議設置**(服務端提供)
// uptoken : '<Your upload token>',
//若未指定uptoken_url,則必須指定 uptoken ,uptoken由其他程序生成
// unique_names: true,
// 默認 false,key為文件名。若開啟該選項,SDK會為每個文件自動生成key(文件名)
// save_key: true,
// 默認 false。若在服務端生成uptoken的上傳策略中指定了 `sava_key`,則開啟,SDK在前端將不對key進行任何處理
domain: 'http://your-bucket-name.qiniudn.com/',//自己的七牛雲存儲空間域名
multi_selection: false,//是否允許同時選擇多文件
//文件類型過濾,這里限制為圖片類型
filters: {
mime_types : [
{title : "Image files", extensions: "jpg,jpeg,gif,png"}
]
},
auto_start: true,
init: {
'FilesAdded': function(up, files) {
//do something
},
'BeforeUpload': function(up, file) {
//do something
},
'UploadProgress': function(up, file) {
//可以在這里控制上傳進度的顯示
//可參考七牛的例子
},
'UploadComplete': function() {
//do something
},
'FileUploaded': function(up, file, info) {
//每個文件上傳成功后,處理相關的事情
//其中 info 是文件上傳成功后,服務端返回的json,形式如
//{
// "hash": "Fh8xVqod2MQ1mocfI4S4KpRL6D98",
// "key": "gogopher.jpg"
//}
var domain = up.getOption('domain');
var res = eval('(' + info + ')');
var sourceLink = domain + res.key;//獲取上傳文件的鏈接地址
//do something
},
'Error': function(up, err, errTip) {
alert(errTip);
},
'Key': function(up, file) {
//當save_key和unique_names設為false時,該方法將被調用
var key = "";
$.ajax({
url: '/qiniu-token/get-key/',
type: 'GET',
async: false,//這里應設置為同步的方式
success: function(data) {
var ext = Qiniu.getFileExtension(file.name);
key = data + '.' + ext;
},
cache: false
});
return key;
}
}
});