前言
在項目中常常會遇到下載或導出服務端資源的需求,通常分爲2種作法
-
獲取文件流,編碼後下載
-
獲取文件的url,直接下載
本文主要探討第二種方法,在最後會說起文件流的方法。
瀏覽器的安全策略
在介紹方法以前,咱們須要知道瀏覽器的一些安全機制,防止惡意代碼對用戶的破壞。
現代瀏覽器(ie8除外)檢測到非用戶直接操做產生的新窗口,通常會阻止,好比在ajax的回調中打開新的窗口,由於這些操做並非在用戶點擊的線程中,因此會攔截。
預開新標籤頁
作法
-
在異步操做以前,先打開一個新標籤頁
-
請求後端資源的地址
-
獲取url後去修改空白頁的url
const downloadTab = window.open('about:blank');
ajax.get('xxx').then(url => {
downloadTab.location.href = href;
}).catch(err => {
downloadTab.close();
})
複製代碼
缺點
-
無論請求成功仍是失敗都會有新頁面的閃爍出現
-
打開的新頁面在何時關閉是個問題,由於若是請求時間過長,用戶可能本身關閉新頁面,更很差處理的狀況是頁面何時觸發了下載,由於若是隻是更改url就關閉窗口可能尚未開始下載的操做。
生成iframe
作法
爲了不頁面閃爍與關閉時機的問題,能夠在當前頁面使用動態建立iframe的方式,直接下載
ajax.get('xxx').then(href => {
if (!href) {
return;
}
if (!this.downIframe) {
this.downIframe = document.createElement('iframe');
this.downIframe.src = href;
this.downIframe.id = 'downloadIframe';
this.downIframe.style.width = '1px';
this.downIframe.style.height = '1px';
this.downIframe.style.position = 'absolute';
this.downIframe.style.left = '-100px';
document.body.appendChild(this.downIframe);
} else {
this.downIframe.src = href;
}
}).catch(err => {
})
複製代碼
缺點
雖然能夠優雅的下載文件了,但是若是須要定製下載文件的名稱就會使人頭疼了,咱們須要時機去改變下載文件的名稱,不然就會使服務端的文件名稱。
生成標籤
利用download屬性設置文件名,
ajax.get('xxx').then(href => {
if (!href) {
return;
}
var a = document.createElement('a');
var url = href;
var filename = 'test.zip';
a.href = url;
a.download = filename;
a.click();
}).catch(err => {
})
複製代碼
注意:
有些瀏覽器須要將a標籤嵌入頁面纔可執行。
處理文件流
最後大概講一下若是後端返回流怎麼處理。
function funDownload(content, filename) {
var link = document.createElement('a');
link.download = filename;
link.style.display = 'none';
var blob = new Blob([content]);
link.href = URL.createObjectURL(blob);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
複製代碼
URL.createObjectURL() 靜態方法會建立一個
DOMString,其中包含一個表示參數中給出的對象的URL。這個 URL 的生命週期和建立它的窗口中的
document 綁定。這個新的URL 對象表示指定的
File 對象或
Blob 對象。
注意:
在每次調用
createObjectURL()
方法時,都會建立一個新的 URL 對象,即便你已經用相同的對象做爲參數建立過。當再也不須要這些 URL 對象時,每一個對象必須經過調用
URL.revokeObjectURL() 方法來釋放。瀏覽器會在文檔退出的時候自動釋放它們,可是爲了得到最佳性能和內存使用情況,你應該在安全的時機主動釋放掉它們。