通過JavaScript下載文件到本地的方法(單文件)
最近在做一個文件下載的功能,這里把做的過程中用的技術(shù)和坑簡要總結(jié)下。
1. 單文件下載(a標(biāo)簽)
同源單文件
針對單文件的情況下,同源的文件,可以通過 < a> 標(biāo)簽的 download 屬性下載文件
const elt = document.createElement('a'); elt.setAttribute('href', url); elt.setAttribute('download', 'file.png'); elt.style.display = 'none'; document.body.appendChild(elt); elt.click(); document.body.removeChild(elt);
但是這個方案并不適用于非同源的資源,此時它相當(dāng)于普通的超鏈接,點擊會跳轉(zhuǎn)到資源頁面,而不是下載。
非同源圖片
如果不存在CORS問題, 可以借助Blob實現(xiàn)下載(構(gòu)造xhr請求文件地址, 以Blob的形式接收Response):
function downloadWithBlob(url) { fetch(url).then(res => res.blob().then(blob => { var a = document.createElement('a'); var url = window.URL.createObjectURL(blob); var filename = 'file.png'; a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url); })); }
如果存在CORS問題,可以考慮使用 canvas 將圖片轉(zhuǎn)換成 base64 編碼之后再通過 標(biāo)簽的 download 屬性下載
function downloadPic(url) { const img = new Image; const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); img.onload = function() { canvas.width = this.width; canvas.height = this.height; ctx.drawImage(this, 0, 0); const elt = document.createElement('a'); elt.setAttribute('href', canvas.toDataURL('image/png')); elt.setAttribute('download', 'file.png'); elt.style.display = 'none'; document.body.appendChild(elt); elt.click(); document.body.removeChild(elt); }; img.crossOrigin = 'anonymous'; img.src = url; }
2. 單文件下載(iframe)
iframe方式是在頁面內(nèi)隱藏iframe, 然后將下載地址加載到iframe中, 從而觸發(fā)瀏覽器的下載行為
const iframe = document.createElement('iframe'); iframe.src = url; iframe.style.display = 'none'; document.body.appendChild(iframe);
但是這里發(fā)現(xiàn),即使是同域的圖片,也無法完成下載,這是為啥呢?
這里就有個上面的a鏈接下載沒有提到的問題:什么樣的鏈接才能觸發(fā)瀏覽器的下載:
url如何觸發(fā)瀏覽器自動下載
一個url能否觸發(fā)瀏覽器自動下載,主要看該請求響應(yīng)頭response header是否滿足,一般是看Content-Disposition和Content-Type這兩個消息頭:
- response header中指定了Content-Disposition為attachment,它表示讓瀏覽器把消息體以附件的形式下載并保存到本地 (一般還會指定filename, 下載的文件名默認(rèn)就是filename)
- response header中指定了Content-Type 為 application/octet-stream(無類型) 或 application/zip(zip包時)等等。(其中 application/octet-stream表示http response為二進制流(沒指定明確的type), 用在未知的應(yīng)用程序文件,瀏覽器一般不會自動執(zhí)行或詢問執(zhí)行。瀏覽器會像對待 設(shè)置了HTTP頭Content-Disposition 值為 attachment 的文件一樣來對待這類文件)
只要url滿足上述觸發(fā)的要求,那么都可以通過iframe的形式來下載
3. 代理服務(wù)處理下載
如果后端自己也能控制的話,或者后端能配合的話,可以寫一個代理服務(wù),在后端去請求文件數(shù)據(jù),然后設(shè)置好相應(yīng)的response header, 然后前端請求代理服務(wù)來做下載。
前端(假設(shè)代理服務(wù)接口是http://exampale.com/download):
const downloadUrl = 'http://exampale.com/download?url=' + encodeURIComponent(url) + '&name=xxx'; const elt = document.createElement('a'); elt.setAttribute('href', downloadUrl); elt.setAttribute('download', 'file.png'); ...
后端
const url = decodeURIComponent(req.query.url); http.get(url, (response) => { res.setHeader('Content-disposition', 'attachment;filename=' + req.query.name); res.setHeader('Content-type', 'application/octet-stream'); response.pipe(res); });
單文件的處理先寫到這里,多文件的下載下篇在寫。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- javascript使用Blob對象實現(xiàn)的下載文件操作示例
- 原生js實現(xiàn)文件上傳、下載、封裝等實例方法
- JavaScript實現(xiàn)文件下載并重命名代碼實例
- php+js實現(xiàn)的無刷新下載文件功能示例
- js使用文件流下載csv文件的實現(xiàn)方法
- Jsp+Servlet實現(xiàn)文件上傳下載 刪除上傳文件(三)
- Jsp+Servlet實現(xiàn)文件上傳下載 文件列表展示(二)
- Jsp+Servlet實現(xiàn)文件上傳下載 文件上傳(一)
- JSP servlet實現(xiàn)文件上傳下載和刪除
- JavaScript實現(xiàn)多文件下載方法解析
相關(guān)文章
深入理解JavaScript系列(46):代碼復(fù)用模式(推薦篇)詳解
這篇文章主要介紹了深入理解JavaScript系列(46):代碼復(fù)用模式(推薦篇)詳解,本文講解了原型繼承、復(fù)制所有屬性進行繼承、混合(mix-in)、借用方法等模式,需要的朋友可以參考下2015-03-03基于substring()和substr()的使用以及區(qū)別(實例講解)
下面小編就為大家分享一篇基于substring()和substr()的使用以及區(qū)別實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12JS實現(xiàn)線性表的順序表示方法示例【經(jīng)典數(shù)據(jù)結(jié)構(gòu)】
這篇文章主要介紹了JS實現(xiàn)線性表的順序表示方法,簡單分析了線性表的原理并結(jié)合實例形式給出了線性表的插入與刪除實現(xiàn)技巧,需要的朋友可以參考下2017-04-04