前端如何實現下載文件呢?隨着前端技術的發展,愈來愈多的前端需求中會出現下載文件這樣的需求。html
看着掘金不少人在近期不斷的分享有關的文章,我總結了下本身的經驗,根據不一樣狀況,總結了一篇算是前端文件下載的通識篇,若是你對這方面徹底不懂或者沒有任何方案,那麼本文會給你一個很不錯的啓示。前端
這種方式是利用form.submit直接向後端提交,後端返回文件流生成的文件,後端處理成功後會直接返回到頁面,瀏覽器會整理並打開本身的保存下載文件機制 。node
優勢 :沒有兼容問題,傳統方式jquery
缺點:拿不到後端處理這個過程的時機,沒法根據回調函數作交互以及進度提示ios
// 後端參考代碼
return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", HttpUtility.UrlEncode("諮詢記錄導出.xls", Encoding.GetEncoding("UTF-8")));
// 參考代碼
function exportRecord() {
var $form = $("<form>"); //定義一個form表單
$form.hide().attr({target:'',method:'post','action':'/xxx'});
var $input = $("<input>");
$input.attr({"type":"hidden","name":'req'}).val(req);
$form.append($input).appendTo($("body")).submit().remove();
}
複製代碼
利用ajax或者新生的axios去提交請求,後端會返回一個線上的文件地址,前端能夠經過原生的window.open打開這個地址就能夠實現下載;也能夠經過a標籤設置href以及download屬性,並自動點擊實現其下載功能,關於其兼容性問題,能夠判斷download屬性是否存在來彌補。git
優勢 :能夠拿到其返回時機,能夠作交互github
缺點 :線上會存儲大量的中間臨時文件,能夠用設置時限來優化。另外涉及用戶隱私的問題,能夠用token等驗證機制實現。web
// 參考方案
$.ajax({
type: "post",
url: "/xxx",
data: data,
success: function (res) {
tool.loadingend();
if(res.Status){
// window.open或者a標籤下載
var isSupportDownload = 'download' in document.createElement('a');
if(isSupportDownload){
var $a = $("<a>") ;
$a.attr({href:res.url,download:'filename'}).hide().appendTo($("body"))[0].click();
}else{
window.open(res.url)
}
}else{
tool.tip(res.Message);
}
}
})
複製代碼
let $form = $("<form>") ;
$form.attr({method:"get",action:res.Message}).hide();
let queryStr = res.Message.split("?")[1];
let queryObj = qs.parse(queryStr) ;
$("body").append($form);
for(let p in queryObj){
let $input =$("<input type='hidden'>") ;
$input.attr({"name":p,value:queryObj[p]}).appendTo($form);
}
$form.submit().remove();
複製代碼
支持場景 : 與上面的方案相比,這個模塊提供的方案更加完善,而不是侷限於某種方案,使用率很高。在源碼中,咱們能夠看到在這個模塊中針對各個瀏覽器和相應的屬性是否支持進行了比較全面的兼容。其對應的下載文件方案包括瞭如下幾種。ajax
方案小結: 對於常規的支持文件地址的下載,兼容性很是好,而對於傳統的文件流性質的,經過form標籤也能夠進行簡單的支持,能夠說是很是好的方案了。固然若是你須要那麼全面的方案,大多數狀況用其中一個就能夠了。數據庫
這個我以爲張鑫旭大佬介紹的蠻多的,應該上手足夠了,就很少介紹了。除了a標籤提供的download屬性,多介紹了一種html:blob的方式。另外針對圖片能夠經過base64的方式。
傳送門:h5新方式下載文件
我的建議:雖然新技術很好,但酌情使用,並且這裏沒有考慮任何兼容,也沒有談論到其餘的一些文件類型,好比表格,pdf,大文件,視頻音頻的下載狀況等。因此不是很建議把這個當作很常規的方案來考慮。
模塊地址:npm.taobao.org/package/fil… github託管地址:github.com/eligrey/Fil…
在模塊的介紹中:詳細說明了瀏覽器支持的狀況,以及能夠支持的下載範圍,保存爲的文件類型,與其咱們去用基礎知識踩雷,仍是建議你們用成熟的模塊方案去解決需求相關的問題。支持不了就退步用傳統的方案解決,讓後端提供直接的文件地址,要知道後端有更多的成熟的技術架包,對於前端來講仍是萌新不肯定的方案,後端早已經有了答案。
說明:咱們以前的需求是但願下載一個表格文件,以前的方案是用後端生成文件地址,而後進行下載,其設置的返回response content type 爲application/vnd.ms-excel (常規類型application/json)。後面發現有這個模塊,基本使用仍是體驗蠻好的,此時的約定變成了後端根據查詢的數據生成一個二進制的文件流,這樣的好處是若是麼有必要的時候能夠減小在阿里雲或者其餘服務器暫存不少文件。
拓展思考下:在你們的公司裏有沒有遇到過相似的需求,按照我以前的經驗是原本是想後端返回一個生成以後的文件地址,但後端的回覆是因爲採用了負載均衡,這個地址再去請求時不必定會請求到這個服務器,因此以前的先後端協調方案是放到了阿里雲,而後經過設置權限和時效來保證文件的臨時性,用戶也能夠在類似請求時不用重複請求數據庫,從新生成文件,由於重複的數據內容會直接返回已經上傳到阿里雲的文件地址。
源碼解析: 在其源碼中,主要是針對返回的http的resonsetype作了要求,而後針對返回的地址進行處理,其中涉及到重要的代碼:
//利用a標籤下載
var a = document.createElement('a')
a.href = blob
//觸發點擊事件
node.dispatchEvent(new MouseEvent('click'))
// reader 進行解析
var reader = new FileReader()
var url = reader.result
//獲得可解析的地址
_global.URL || _global.webkitURL,
URL.createObjectURL(blob)
//對 cors 跨域是否支持
return xhr.status >= 200 && xhr.status <= 299
複製代碼
filereader的官方介紹:developer.mozilla.org/zh-CN/docs/…
綜上,不管是偏傳統的方案,仍是比較全面兼容的根據文件地址下載的方式,仍是h5新出的webapi的方式都有比較好的認識,若是你對相關的知識點或者方案有進一步研究的興趣,建議針對官方api的相關文章或者已經開源出的兩個模塊進行深度的優化和研究效率更佳。
以爲還不錯,給個贊加關注吧,謝謝你們的支持。