前端文件下載通識篇

前言

前端如何實(shí)現(xiàn)下載文件呢?隨著前端技術(shù)的發(fā)展捌刮,越來越多的前端需求中會(huì)出現(xiàn)下載文件這樣的需求。

看著掘金很多人在近期不斷的分享有關(guān)的文章舒岸,我總結(jié)了下自己的經(jīng)驗(yàn)绅作,根據(jù)不同情況,總結(jié)了一篇算是前端文件下載的通識篇蛾派,如果你對這方面完全不懂或者沒有任何方案俄认,那么本文會(huì)給你一個(gè)很不錯(cuò)的啟示。

方案一 :原生提交洪乍,后端返回文件流

這種方式是利用form.submit直接向后端提交,后端返回文件流生成的文件眯杏,后端處理成功后會(huì)直接返回到頁面,瀏覽器會(huì)整理并打開自己的保存下載文件機(jī)制 典尾。

優(yōu)點(diǎn) :沒有兼容問題役拴,傳統(tǒng)方式

缺點(diǎn):拿不到后端處理這個(gè)過程的時(shí)機(jī)糊探,無法根據(jù)回調(diào)函數(shù)做交互以及進(jìn)度提示

// 后端參考代碼
return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", HttpUtility.UrlEncode("咨詢記錄導(dǎo)出.xls", Encoding.GetEncoding("UTF-8")));
// 參考代碼
function exportRecord() {
   var $form = $("<form>"); //定義一個(gè)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提交钾埂,后端返回在線文件地址

利用ajax或者新生的axios去提交請求,后端會(huì)返回一個(gè)線上的文件地址科平,前端可以通過原生的window.open打開這個(gè)地址就可以實(shí)現(xiàn)下載褥紫;也可以通過a標(biāo)簽設(shè)置href以及download屬性,并自動(dòng)點(diǎn)擊實(shí)現(xiàn)其下載功能瞪慧,關(guān)于其兼容性問題髓考,可以判斷download屬性是否存在來彌補(bǔ)。

優(yōu)點(diǎn) :可以拿到其返回時(shí)機(jī)弃酌,可以做交互

缺點(diǎn) :線上會(huì)存儲(chǔ)大量的中間臨時(shí)文件氨菇,可以用設(shè)置時(shí)限來優(yōu)化。另外涉及用戶隱私的問題妓湘,可以用token等驗(yàn)證機(jī)制實(shí)現(xiàn)查蓉。

// 參考方案
$.ajax({
                type: "post",
                url: "/xxx",
                data: data,
                success: function (res) {
                    tool.loadingend();
                    if(res.Status){
                    // window.open或者a標(biāo)簽下載 
                    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);
                    }
                }
            })
  • a標(biāo)簽download屬性
  • 方案二 :補(bǔ)充方案 :利用form表單提交下載文件(ajax無法直接處理返回的文件類型),用于解決window.open方案被瀏覽器攔截的情況。
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(); 

方案三 :前端利用download模塊進(jìn)行下載

支持場景
與上面的方案相比榜贴,這個(gè)模塊提供的方案更加完善豌研,而不是局限于某種方案,使用率很高唬党。在源碼中鹃共,我們可以看到在這個(gè)模塊中針對各個(gè)瀏覽器和相應(yīng)的屬性是否支持進(jìn)行了比較全面的兼容。其對應(yīng)的下載文件方案包括了以下幾種驶拱。

  • window.open(url)打開某個(gè)文件地址
  • iframe的框架中霜浴,設(shè)置src屬性,通過iframe進(jìn)行文件的下載蓝纲,支持文件地址
  • 通過form標(biāo)簽阴孟,設(shè)置action的文件地址房铭,然后通過form的提交來完成文件的下載(支持二進(jìn)制)

方案小結(jié):
對于常規(guī)的支持文件地址的下載,兼容性非常好温眉,而對于傳統(tǒng)的文件流性質(zhì)的缸匪,通過form標(biāo)簽也可以進(jìn)行簡單的支持,可以說是非常好的方案了类溢。當(dāng)然如果你需要那么全面的方案凌蔬,大多數(shù)情況用其中一個(gè)就可以了。

方案四 :h5新生方案下載

這個(gè)我覺得張鑫旭大佬介紹的蠻多的闯冷,應(yīng)該上手足夠了砂心,就不多介紹了。除了a標(biāo)簽提供的download屬性蛇耀,多介紹了一種html:blob的方式辩诞。另外針對圖片可以通過base64的方式。

傳送門:h5新方式下載文件

個(gè)人建議:雖然新技術(shù)很好纺涤,但酌情使用译暂,而且這里沒有考慮任何兼容,也沒有談?wù)摰狡渌囊恍┪募愋土么叮热绫砀裢庥溃琾df,大文件拧咳,視頻音頻的下載情況等伯顶。所以不是很建議把這個(gè)當(dāng)做很常規(guī)的方案來考慮。

方案五 :file-saver

模塊地址https://npm.taobao.org/package/file-saver骆膝,推薦使用祭衩,下載量以及穩(wěn)定性足夠好。支持新出的h5特性的加載方式阅签,也就是方案五的部分掐暮。
github托管地址:https://github.com/eligrey/FileSaver.js

在模塊的介紹中:詳細(xì)說明了瀏覽器支持的情況,以及可以支持的下載范圍愉择,保存為的文件類型劫乱,與其我們?nèi)ビ没A(chǔ)知識踩雷,還是建議大家用成熟的模塊方案去解決需求相關(guān)的問題锥涕。支持不了就退步用傳統(tǒng)的方案解決衷戈,讓后端提供直接的文件地址,要知道后端有更多的成熟的技術(shù)架包层坠,對于前端來說還是萌新不確定的方案殖妇,后端早已經(jīng)有了答案。

說明:我們之前的需求是希望下載一個(gè)表格文件破花,之前的方案是用后端生成文件地址谦趣,然后進(jìn)行下載疲吸,其設(shè)置的返回response content type 為application/vnd.ms-excel (常規(guī)類型application/json)。后面發(fā)現(xiàn)有這個(gè)模塊前鹅,基本使用還是體驗(yàn)蠻好的摘悴,此時(shí)的約定變成了后端根據(jù)查詢的數(shù)據(jù)生成一個(gè)二進(jìn)制的文件流,這樣的好處是如果么有必要的時(shí)候可以減少在阿里云或者其他服務(wù)器暫存很多文件舰绘。

拓展思考下:在大家的公司里有沒有遇到過類似的需求蹂喻,按照我之前的經(jīng)驗(yàn)是本來是想后端返回一個(gè)生成之后的文件地址,但后端的回復(fù)是由于采用了負(fù)載均衡捂寿,這個(gè)地址再去請求時(shí)不一定會(huì)請求到這個(gè)服務(wù)器口四,所以之前的前后端協(xié)調(diào)方案是放到了阿里云,然后通過設(shè)置權(quán)限和時(shí)效來保證文件的臨時(shí)性秦陋,用戶也可以在相似請求時(shí)不用重復(fù)請求數(shù)據(jù)庫蔓彩,重新生成文件,因?yàn)橹貜?fù)的數(shù)據(jù)內(nèi)容會(huì)直接返回已經(jīng)上傳到阿里云的文件地址驳概。

源碼解析:
在其源碼中赤嚼,主要是針對返回的http的resonsetype做了要求,然后針對返回的地址進(jìn)行處理抡句,其中涉及到重要的代碼:

//利用a標(biāo)簽下載
var a = document.createElement('a')
a.href = blob
//觸發(fā)點(diǎn)擊事件
node.dispatchEvent(new MouseEvent('click'))
// reader 進(jìn)行解析
var reader = new FileReader()
var url = reader.result
//得到可解析的地址
_global.URL || _global.webkitURL探膊,
URL.createObjectURL(blob)
//對 cors 跨域是否支持
  return xhr.status >= 200 && xhr.status <= 299

filereader的官方介紹:https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader

總結(jié)

綜上,無論是偏傳統(tǒng)的方案待榔,還是比較全面兼容的根據(jù)文件地址下載的方式,還是h5新出的webapi的方式都有比較好的認(rèn)識流济,如果你對相關(guān)的知識點(diǎn)或者方案有進(jìn)一步研究的興趣锐锣,建議針對官方api的相關(guān)文章或者已經(jīng)開源出的兩個(gè)模塊進(jìn)行深度的優(yōu)化和研究效率更佳。

覺得還不錯(cuò)绳瘟,給個(gè)贊加關(guān)注吧雕憔,謝謝大家的支持。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末糖声,一起剝皮案震驚了整個(gè)濱河市斤彼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蘸泻,老刑警劉巖琉苇,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異悦施,居然都是意外死亡并扇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門抡诞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來穷蛹,“玉大人土陪,你說我怎么就攤上這事‰妊” “怎么了鬼雀?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蛙吏。 經(jīng)常有香客問我取刃,道長,這世上最難降的妖魔是什么出刷? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任璧疗,我火速辦了婚禮,結(jié)果婚禮上馁龟,老公的妹妹穿的比我還像新娘崩侠。我一直安慰自己,他們只是感情好坷檩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布却音。 她就那樣靜靜地躺著,像睡著了一般矢炼。 火紅的嫁衣襯著肌膚如雪系瓢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天句灌,我揣著相機(jī)與錄音夷陋,去河邊找鬼。 笑死胰锌,一個(gè)胖子當(dāng)著我的面吹牛骗绕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播资昧,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼酬土,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了格带?” 一聲冷哼從身側(cè)響起倦始,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤升酣,失蹤者是張志新(化名)和其女友劉穎荡陷,沒想到半個(gè)月后狡恬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尔觉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年凉袱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡专甩,死狀恐怖钟鸵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涤躲,我是刑警寧澤棺耍,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站种樱,受9級特大地震影響蒙袍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嫩挤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一害幅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧岂昭,春花似錦以现、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至恰矩,卻和暖如春记盒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背外傅。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工纪吮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人栏豺。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓彬碱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親奥洼。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,080評論 25 707
  • 用兩張圖告訴你晚胡,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料灵奖? 從這篇文章中你...
    hw1212閱讀 12,714評論 2 59
  • 青海湖 前兩天的旅游我還在暗暗自喜瓷患,自己體質(zhì)不錯(cuò)沒有一點(diǎn)高原反應(yīng),沒想第三天入住在藏區(qū)的青海湖畔的夜晚遣妥,我卻頭疼地...
    徜徉未來閱讀 358評論 1 1
  • 努力機(jī)敏敢于放棄 對中下差生 具體抽象半抽象 半扶不扶 魚的記憶職業(yè)事業(yè)師德 智慧能力苦難的意義美酒信仰 睡裝睡醒...
    pretty1994閱讀 85評論 0 0
  • 方世平—8月18日分析 加拿大7月份消費(fèi)者物價(jià)指數(shù)(CPI)年率上升了3%,遠(yuǎn)高于2.5%的預(yù)期爱态,也是自2011年...
    方世平閱讀 214評論 0 0