摘要:最近在做一個文件下載的功能,這里把做的過程中用的技術和坑簡要總結(jié)下。前端假設代理服務接口是后端單文件的處理先寫到這里,多文件的下載下篇在寫。
最近在做一個文件下載的功能,這里把做的過程中用的技術和坑簡要總結(jié)下。1. 單文件下載(a標簽) 同源單文件
針對單文件的情況下,同源的文件,可以通過 < a> 標簽的 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);
但是這個方案并不適用于非同源的資源,此時它相當于普通的超鏈接,點擊會跳轉(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 編碼之后再通過 標簽的 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ā)瀏覽器自動下載,主要看該請求響應頭response header是否滿足,一般是看Content-Disposition和Content-Type這兩個消息頭:
response header中指定了Content-Disposition為attachment,它表示讓瀏覽器把消息體以附件的形式下載并保存到本地 (一般還會指定filename, 下載的文件名默認就是filename)
response header中指定了Content-Type 為 application/octet-stream(無類型) 或 application/zip(zip包時)等等。(其中 application/octet-stream表示http response為二進制流(沒指定明確的type), 用在未知的應用程序文件,瀏覽器一般不會自動執(zhí)行或詢問執(zhí)行。瀏覽器會像對待 設置了HTTP頭Content-Disposition 值為 attachment 的文件一樣來對待這類文件)
只要url滿足上述觸發(fā)的要求,那么都可以通過iframe的形式來下載
3. 代理服務處理下載如果后端自己也能控制的話,或者后端能配合的話,可以寫一個代理服務,在后端去請求文件數(shù)據(jù),然后設置好相應的response header, 然后前端請求代理服務來做下載。
前端(假設代理服務接口是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); });
單文件的處理先寫到這里,多文件的下載下篇在寫。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/102517.html
摘要:包批量下載雖然說可以遍歷所有文件,然后去批量下載單個文件,但是這種體驗畢竟不太好,最常見的做法是把批量的文件下載并打包到中。 最近在做一個文件下載的功能,這里把做的過程中用的技術和坑簡要總結(jié)下。上篇文章《通過 JavaScript 下載文件到本地(單文件)》說了下如何下載單文件,這篇主要說下如何做多文件的批量下載 多文件分別處理 如果文件數(shù)量可控,對于下載出來的文件格式無要求,可以用最...
摘要:基礎篇整合最近有朋友也想學習相關方面的知識,如果你是后端想接近前端,作為一門跑在服務端的語言從這里入門再好不過了。事件驅(qū)動機制是通過內(nèi)部單線程高效率地維護事件循環(huán)隊列來實現(xiàn)的,沒有多線程的資源占用和上下文的切換。 nodeJs 基礎篇整合 最近有朋友也想學習nodeJs相關方面的知識,如果你是后端想接近前端,node作為一門跑在服務端的JS語言從這里入門再好不過了。如果你正好喜歡前端,...
摘要:基礎篇整合最近有朋友也想學習相關方面的知識,如果你是后端想接近前端,作為一門跑在服務端的語言從這里入門再好不過了。事件驅(qū)動機制是通過內(nèi)部單線程高效率地維護事件循環(huán)隊列來實現(xiàn)的,沒有多線程的資源占用和上下文的切換。 nodeJs 基礎篇整合 最近有朋友也想學習nodeJs相關方面的知識,如果你是后端想接近前端,node作為一門跑在服務端的JS語言從這里入門再好不過了。如果你正好喜歡前端,...
摘要:基礎篇整合最近有朋友也想學習相關方面的知識,如果你是后端想接近前端,作為一門跑在服務端的語言從這里入門再好不過了。事件驅(qū)動機制是通過內(nèi)部單線程高效率地維護事件循環(huán)隊列來實現(xiàn)的,沒有多線程的資源占用和上下文的切換。 nodeJs 基礎篇整合 最近有朋友也想學習nodeJs相關方面的知識,如果你是后端想接近前端,node作為一門跑在服務端的JS語言從這里入門再好不過了。如果你正好喜歡前端,...
閱讀 1363·2021-09-02 10:19
閱讀 1104·2019-08-26 13:25
閱讀 2114·2019-08-26 11:37
閱讀 2420·2019-08-26 10:18
閱讀 2681·2019-08-23 16:43
閱讀 3007·2019-08-23 16:25
閱讀 781·2019-08-23 15:53
閱讀 3302·2019-08-23 15:11