前端學(xué)習(xí)隨記の下載上傳篇 —— 下載篇
閑言: 懶懶懶!I亍香缺!好長(zhǎng)時(shí)間不寫文章了,一直出差魔都歇僧,學(xué)習(xí)一些其他知識(shí)開發(fā)項(xiàng)目图张,也時(shí)不時(shí)的空閑時(shí)間深度學(xué)習(xí)一些前端基礎(chǔ)知識(shí)锋拖。好吧,不找理由祸轮,就是懶哇哈哈(????)兽埃。
參考傳送門:
http://www.cnblogs.com/voiphudong/p/3284724.html
https://scarletsky.github.io/2016/07/03/download-file-using-javascript/#參考資料
https://developer.mozilla.org/zh-CN/docs/Web/API/FileSystem
引言###
上傳下載一直是項(xiàng)目上非常常見的需求,也是對(duì)于我這種前端小白來(lái)說(shuō)一直隱隱犯怵的地方适袜,不太熟悉柄错,加上項(xiàng)目上用過(guò)一次,同事朋友也問過(guò)遇到過(guò)苦酱,所以打算好好惡補(bǔ)這塊↖(ω)↗售貌。本篇先說(shuō)下下載,上傳留著下篇來(lái)說(shuō)疫萤,歡迎關(guān)注留bug.
幾種下載方式
前后端下載方式原理簡(jiǎn)述:
1)標(biāo)準(zhǔn)URL下載方式:?可以通過(guò)在web頁(yè)面中嵌入 url超級(jí)鏈接颂跨,標(biāo)準(zhǔn)的HTTP GET請(qǐng)求。對(duì)于服務(wù)器端web根目錄有一個(gè)test.zip的文件扯饶。此種方法的弊端是完全暴露了文件test.zip的網(wǎng)站路徑恒削,而且動(dòng)態(tài)性不夠靈活。
2)通過(guò)服務(wù)器端腳本向?yàn)g覽器方(stdout)輸出二進(jìn)制流的方式下載:?上述方法可以在服務(wù)器端 通過(guò) 腳本程序 download.php 尾序,并且根據(jù)傳入的查詢字符串f=test.zip定位服務(wù)器上文件系統(tǒng)test.zip的路徑钓丰,然后按二進(jìn)制流的方式發(fā)送給客戶端瀏覽器,那么客戶端瀏覽器就會(huì)彈出一個(gè)“下載對(duì)話框”了每币。
form 表單下載
POST的URL下載鏈接携丁,可以通過(guò)設(shè)置form表單的action 以及 表單元素值來(lái)完成下載。
function downLoad () {
var form = document.createElement('form'); //定義一個(gè)form表單
form.style = 'display:none'; //下面為在form表單中添加查詢參數(shù)
form.target = '';
form.method = 'post';
form.action = url;//下載接口
var input1 = document.createElement('input');
input1.type = 'hidden';
Input1.name = 'exportData';
input1.value = (new Date()).getMilliseconds();
document.body.appendChild(form) //將表單放置在web中
form.appendChild(input1); //將查詢參數(shù)控件提交到表單上
form.submit(); //表單提交
}
iframe
iframe有一個(gè)src屬性脯爪,其本質(zhì)就是發(fā)送http請(qǐng)求则北,GET一個(gè)頁(yè)面或者數(shù)據(jù),可以通過(guò)一個(gè)動(dòng)態(tài)生成的隱藏的iframe來(lái)得到下載的二進(jìn)制文件。
function download(){
var IFrameRequest=document.createElement("iframe");
IFrameRequest.id="IFrameRequest";
IFrameRequest.src="/test.zip";
IFrameRequest.style.display="none";
document.body.appendChild(IFrameRequest);
}
HTML5のdownload屬性
由于瀏覽器的安全策略的限制痕慢,我們通常只能通過(guò)一個(gè)額外的頁(yè)面,訪問某個(gè)文件的 url 來(lái)實(shí)現(xiàn)下載功能涌矢,但是這種用戶體驗(yàn)非常不好掖举。HTML 5 里面為 a 標(biāo)簽添加了一個(gè) download 的屬性,我們可以輕易的利用它來(lái)實(shí)現(xiàn)下載功能娜庇。
<a href="http://somehost/somefile.zip" download="filename.zip">Download file</a>
a標(biāo)簽添加 download 屬性塔次,我們點(diǎn)擊這個(gè)鏈接的時(shí)候就會(huì)自動(dòng)下載文件了~
順便說(shuō)下,download 的屬性值是可選的名秀,它用來(lái)指定下載文件的文件名励负。像上面的例子中,我們下載到本地的文件名就會(huì)是 filename.zip 拉匕得,如果不指定的話继榆,它就會(huì)是 somefile.zip 這個(gè)名字啦巾表!
當(dāng)然,我們還可以動(dòng)態(tài)創(chuàng)建a標(biāo)簽實(shí)現(xiàn)下載:
function download() {
var a = document.createElement('a');
var url = window.URL.createObjectURL(blob);
var filename = 'what-you-want.txt';
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}
window.URL 里面有兩個(gè)方法:
createObjectURL 用 blob 對(duì)象來(lái)創(chuàng)建一個(gè) object URL(它是一個(gè) DOMString)略吨,我們可以用這個(gè) object URL 來(lái)表示某個(gè) blob 對(duì)象集币,這個(gè) object URL 可以用在 href 和 src 之類的屬性上。
revokeObjectURL 釋放由 createObjectURL 創(chuàng)建的 object URL翠忠,當(dāng)該 object URL 不需要的時(shí)候鞠苟,我們要主動(dòng)調(diào)用這個(gè)方法來(lái)獲取最佳性能和內(nèi)存使用。
當(dāng)然秽之,如果你沒有blob對(duì)象的url,也可以不用window.URL当娱,直接使用下載地址url。
HTML5のFileSystem
由于這種方法目前大多數(shù)瀏覽器不支持考榨,僅僅chrome支持跨细,具體方式可以查看大神們的文章,我就不搬運(yùn)了董虱。(????)
https://imququ.com/post/a-downloader-with-filesystem-api.html
其他方式
Window.open(url):這種方式在目前的網(wǎng)絡(luò)環(huán)境及安全限制下被攔截已經(jīng)不太好使了扼鞋,主要用來(lái)是打開新窗口下載。
var new_window = null;
function downLoad () {
var isSure=confirm("是否下載")
if (isSure){
new_window = window.open()
new_window.location.;
document.getElementById('result').innerHTML = "You downLoad OK!"
}
else{
document.getElementById('result').innerHTML = "You pressed Cancel!"
}
}
function closeDownLoad() {
new_window && new_window.close();
}
//使用a鏈接target='_blank'愤诱,則不會(huì)攔截下載
function AdownLoad() {
var url = 'https://github.com/WZOnePiece/study-draggable/archive/master.zip';
var a = document.createElement("a");
a.setAttribute("href", url);
a.setAttribute("target", "_blank");
a.setAttribute("id", "camnpr");
document.body.appendChild(a);
a.click();
}
這里主要是用window.open 打開窗口云头,接著使用location.href = url進(jìn)行重定向避免攔截進(jìn)行下載。
補(bǔ)充知識(shí)
Blob 對(duì)象
Blob 全稱是 Binary large object淫半,它表示一個(gè)類文件對(duì)象溃槐,可以用它來(lái)表示一個(gè)文件。根據(jù) MDN 上面的說(shuō)法科吭,F(xiàn)ile API 也是基于 blob 來(lái)實(shí)現(xiàn)的昏滴。
構(gòu)建 blob 的方式就是通過(guò)服務(wù)器返回的文件來(lái)創(chuàng)建 blob ,采用File API及Fetch API对人。
fetch('http://somehost/somefile.zip').then(res => res.blob().then(blob => {
var a = document.createElement('a');
var url = window.URL.createObjectURL(blob);
var filename = 'myfile.zip';
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}))
注意:Fetch API 目前瀏覽器支持不好谣殊,詳情看https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
File API的詳細(xì)介紹:https://developer.mozilla.org/zh-CN/docs/Using_files_from_web_applications
可以利用fetch配合reader對(duì)象來(lái)實(shí)現(xiàn)進(jìn)度條功能
限制
1、不同瀏覽器對(duì) blob 對(duì)象有不同的限制
Supported browsers
Browser | Constructs as | Filenames | Max Blob Size | Dependencies |
---|---|---|---|---|
Firefox 20+ | Blob | Yes | 800 MiB | None |
Firefox < 20 | data: URI | No | n/a | Blob.js |
Chrome | Blob | Yes | [500 MiB][3] | None |
Chrome for Android | Blob | Yes | [500 MiB][3] | None |
Edge | Blob | Yes | ? | None |
IE 10+ | Blob | Yes | 600 MiB | None |
Opera 15+ | Blob | Yes | 500 MiB | None |
Opera < 15 | data: URI | No | n/a | Blob.js |
Safari 6.1+* | Blob | No | ? | None |
Safari < 6 | data: URI | No | n/a | Blob.js |
2牺弄、構(gòu)建完 blob 對(duì)象后才會(huì)轉(zhuǎn)換成文件姻几。
文件大點(diǎn)的話,要等到下載完文件之后才能構(gòu)建 blob 對(duì)象势告,再轉(zhuǎn)化成文件蛇捌,頁(yè)面顯示上不太友好,沒有提示咱台。這時(shí)建議采用a標(biāo)簽络拌,防止用戶的錯(cuò)誤認(rèn)知造成重復(fù)點(diǎn)擊下載,資源浪費(fèi)回溺。
服務(wù)器出錯(cuò)
- 1春贸、window.open(url)
打開一個(gè)帶錯(cuò)誤信息的頁(yè)面
- 2混萝、window.location.href
頁(yè)面將跳轉(zhuǎn)到一個(gè)錯(cuò)誤頁(yè)面
- 3、iframe
用戶感知不到任何變化
- 4祥诽、a標(biāo)簽
直接出現(xiàn) 下載失敗
當(dāng)然譬圣,如果response header里有content-disposition字段的話,瀏覽器都會(huì)下載一個(gè)帶錯(cuò)誤信息的文件雄坪。這時(shí)候厘熟,其實(shí)我們可以多發(fā)一個(gè)ajax/fetch請(qǐng)求,先檢測(cè)下接口狀態(tài)维哈,然后再取做下載邏輯绳姨。但這樣就對(duì)服務(wù)器造成了額外的開銷。
這樣的體驗(yàn)都不太好阔挠,作為一個(gè)追求極致體驗(yàn)的程序猿飘庄,我們應(yīng)該重新思考下,如何提升用戶體驗(yàn)购撼。
結(jié)語(yǔ)##
O(∩_∩)O跪削,這篇下載篇就這樣簡(jiǎn)單介紹下,至于還有其他的方式迂求,歡迎留言告知碾盐;代碼及描述上有bug也希望不吝指出。謝謝哈揩局!