摘要:三瀏覽器方式相信大家對(duì)這個(gè)對(duì)象也不太陌生,它是標(biāo)準(zhǔn)里的一個(gè)二進(jìn)制數(shù)據(jù)對(duì)象,可以與對(duì)象配合,進(jìn)行文件的下載。其實(shí)這樣一個(gè)簡(jiǎn)單的,就可以實(shí)現(xiàn)瀏覽器端自己的下載了。
一、背景
最近寫(xiě)了一個(gè)react的組件,用來(lái)做文件導(dǎo)出。環(huán)境是ie10+。
細(xì)一點(diǎn)說(shuō),就是
1、讀取form里的數(shù)據(jù)
2、向服務(wù)端發(fā)請(qǐng)求,并下載文件;要求拿到請(qǐng)求狀態(tài),如果出錯(cuò)及時(shí)反饋給用戶。
第一個(gè)需求,我們借用了jquery的serializeArray方法,畢竟我們不想再造輪子。那接下來(lái)重點(diǎn)說(shuō)說(shuō)后面的需求。
二、一般下載文件方式大家在下載的問(wèn)題的時(shí)候,一般來(lái)說(shuō),會(huì)用到
1、window.open(url);
2、window.location.href = url;
3、iframe,其實(shí)與window.open類似,但不用開(kāi)啟新的tab
4、a 標(biāo)簽,利用download屬性
這些方法,其實(shí)極度依賴服務(wù)端的正確性。我們可以看看服務(wù)端一旦出錯(cuò)的結(jié)果。
1、window.open(url)
打開(kāi)一個(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ù)器造成了額外的開(kāi)銷。
這樣的體驗(yàn)都不太好,作為一個(gè)追求極致體驗(yàn)的程序猿,我們應(yīng)該重新思考下,如何提升用戶體驗(yàn)。
三、瀏覽器FileAPI方式相信大家對(duì)blob這個(gè)對(duì)象也不太陌生,它是html5標(biāo)準(zhǔn)里的一個(gè)二進(jìn)制數(shù)據(jù)對(duì)象,可以與URL 對(duì)象配合,進(jìn)行文件的下載。
下面是一個(gè)最簡(jiǎn)單的demo(我們暫時(shí)不考慮瀏覽器兼容問(wèn)題)。
let blob2 = new Blob(["123"]); let url = URL.createObjectURL(blob2); let a = document.createElement("a"); a.download = "test"; a.href = url; a.click();
其實(shí)這樣一個(gè)簡(jiǎn)單的demo,就可以實(shí)現(xiàn)瀏覽器端自己的下載了。那如何從服務(wù)端拿到數(shù)據(jù),并下載呢?
這里,我們拿服務(wù)端數(shù)據(jù),主要是通過(guò)fetch,fetch提供了一些api。其中就有一個(gè)blob的promise,我們可以把返回的數(shù)據(jù)轉(zhuǎn)成blob對(duì)象,這樣就能去下載文件了。
回到最初的需求,我們需要檢測(cè)接口的狀態(tài)。其實(shí)通過(guò)fetch,我們完全可以拿到response的信息,既然都能拿到,那控制權(quán)就在我們自手上了。
四、額外收獲-進(jìn)度條按照FileApi的方式,我們是一次性從服務(wù)端拿到數(shù)據(jù),然后再在瀏覽器端進(jìn)行操作。既然是這樣,那拿數(shù)據(jù)的過(guò)程是不是就可以顯示出進(jìn)度呢?這個(gè)特性,我們用以前傳統(tǒng)的下載方式是完全做不到的。
關(guān)于進(jìn)度條,我們可以利用fetch配合reader對(duì)象來(lái)實(shí)現(xiàn)進(jìn)度條功能,如下:
fetch(url).then(response => { var reader = response.body.getReader(); var headers = response.headers; var totalLength = headers.get("Content-Length"); var bytesReceived = 0; reader.read().then(function processResult(result) { if (result.done) { return; } bytesReceived += result.value.length; console.log(`progress: ${bytesReceived / totalLength * 100}%`); return reader.read().then(processResult); }); });
當(dāng)然,有人可能會(huì)說(shuō)ie下fetch會(huì)有問(wèn)題。沒(méi)錯(cuò),確實(shí)會(huì)有問(wèn)題,但這時(shí)候我們可以用XMLHttpRequest這個(gè)對(duì)象來(lái)實(shí)現(xiàn),會(huì)更簡(jiǎn)單直接一點(diǎn)。
五、常見(jiàn)問(wèn)題 1、filename通過(guò)fileapi的方式下載文件,有個(gè)很重要的問(wèn)題,就是文件名。最初的一些下載方式,都是瀏覽器自己通過(guò)判斷content-disposition這個(gè)字段來(lái)讀取文件名。那現(xiàn)在不一樣了,我們需要自己來(lái)讀取文件名,這時(shí)候難免要自己讀這個(gè)header,通過(guò)正則匹配下文件名。
2、cors關(guān)于cors問(wèn)題,其實(shí)只要是異步請(qǐng)求,都會(huì)碰到。新版瀏覽器,我們常用access-control-allow-origin這個(gè)字段來(lái)解決跨域問(wèn)題。這時(shí)候,我們?cè)谧x文件名的可能要留一點(diǎn),記得在header里加上Access-Control-Expose-Headers這個(gè)字段,不然fetch是取不到filename信息的。具體可以看看這篇doc
3、大文件下載問(wèn)題在用fileapi的時(shí)候,我們發(fā)現(xiàn)文件過(guò)大會(huì)讓瀏覽器崩潰,會(huì)導(dǎo)致文件下載失敗。目前我在測(cè)試500mb以上的文件的時(shí)候就會(huì)碰到這樣的情況。這個(gè)問(wèn)題,可以通過(guò)webkitrequestfilesystem這個(gè)對(duì)象來(lái)曲線解決,但這并不是一個(gè)standard api,目前只有新版chrome支持這個(gè)對(duì)象,所以盡量不要去用。
我們推薦在拿到response的時(shí)候,讀取一下blob的size,如果發(fā)現(xiàn)太大,就進(jìn)行降級(jí)處理,使用我們最初的那中方式。
五、總結(jié)我一直相信no silver bullet這句話,雖然fileapi這種方式能解決部分問(wèn)題,但其實(shí)也有很多缺點(diǎn),相信大家會(huì)在實(shí)際場(chǎng)景中會(huì)更深刻的感受到。所以在設(shè)計(jì)組件的時(shí)候,我們?cè)谧龊脙?yōu)雅降級(jí)的方案同時(shí),還特意為大家開(kāi)放了各種下載方式,以適應(yīng)各種場(chǎng)景。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/79439.html
摘要:年初,許多事件使得被大眾所接受。這使得應(yīng)用程序更為迅捷地響應(yīng)用戶交互,并避免了在網(wǎng)絡(luò)上發(fā)送那些沒(méi)有改變的信息,減少用戶等待時(shí)間,帶來(lái)非常好的用戶體驗(yàn)。調(diào)用方法后立即觸發(fā),若未被調(diào)用則不會(huì)觸發(fā)此事件。 了解Ajax的起源、概念及特點(diǎn) 起源 該技術(shù)在1998年前后得到了應(yīng)用。允許客戶端腳本發(fā)送HTTP請(qǐng)求(XMLHTTP)的第一個(gè)組件由Outlook Web Access小組寫(xiě)成。該組...
摘要:年初,許多事件使得被大眾所接受。這使得應(yīng)用程序更為迅捷地響應(yīng)用戶交互,并避免了在網(wǎng)絡(luò)上發(fā)送那些沒(méi)有改變的信息,減少用戶等待時(shí)間,帶來(lái)非常好的用戶體驗(yàn)。調(diào)用方法后立即觸發(fā),若未被調(diào)用則不會(huì)觸發(fā)此事件。 了解Ajax的起源、概念及特點(diǎn) 起源 該技術(shù)在1998年前后得到了應(yīng)用。允許客戶端腳本發(fā)送HTTP請(qǐng)求(XMLHTTP)的第一個(gè)組件由Outlook Web Access小組寫(xiě)成。該組...
摘要:年初,許多事件使得被大眾所接受。這使得應(yīng)用程序更為迅捷地響應(yīng)用戶交互,并避免了在網(wǎng)絡(luò)上發(fā)送那些沒(méi)有改變的信息,減少用戶等待時(shí)間,帶來(lái)非常好的用戶體驗(yàn)。調(diào)用方法后立即觸發(fā),若未被調(diào)用則不會(huì)觸發(fā)此事件。 了解Ajax的起源、概念及特點(diǎn) 起源 該技術(shù)在1998年前后得到了應(yīng)用。允許客戶端腳本發(fā)送HTTP請(qǐng)求(XMLHTTP)的第一個(gè)組件由Outlook Web Access小組寫(xiě)成。該組...
閱讀 1346·2023-04-25 19:35
閱讀 3156·2021-11-22 09:34
閱讀 4010·2021-10-09 09:44
閱讀 1823·2021-09-22 15:25
閱讀 3015·2019-08-29 14:00
閱讀 3471·2019-08-29 11:01
閱讀 2702·2019-08-26 13:26
閱讀 1825·2019-08-23 18:08