JS下載檔案常用的方式
阿新 • • 發佈:2019-01-13
下載附件(image,doc,docx, excel,zip,pdf),應該是實際工作中經常遇到一個問題;這裡使用過幾種方式分享出來僅供參考; 初次寫可能存在問題,有問題望指出
主要了解的幾個知識點:
-
http 響應頭設定
- Content-Disposition
- Access-Control-Expose-Headers 這裡只需要涉及跨域的時才使用,用於暴露JavaScript中能夠獲取到響應頭欄位
- Blob 、 FileReader
- URL
先來介紹常用方式: 這裡下載.doc文件為例,其它都類似
利用 iframe 或 a 連線
服務端程式碼
// nodejs const http = require('http'); const fs = require('fs'); const path = require('path'); http.createServer(function (req, res) { let filename = encodeURIComponent('微信多開的步驟.doc'); // 下面兩個主要在跨域情況下,需要設定的 res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Expose-Headers', 'Content-Disposition'); // 設定響應頭 res.setHeader('Content-Type', 'application/zip;charset=UTF-8'); res.setHeader('Content-Disposition', `attachment; filename=${filename}`); let fs.readFile(path.resolve(__dirname, `./微信多開的步驟.doc`), function (err, data) { if (err) throw err; res.end(data);}); }).listen(3000);
Content-Disposition
訊息頭指示回覆的內容該以何種形式展示,是以內聯的形式(即網頁或者頁面的一部分),還是以附件的形式下載並儲存到本地。
大概流程:
1 下載時瀏覽器會嘗試去找下響應頭中 Content-Disposition
;
2 如果不存在,首先嚐試去預覽方式開啟該檔案 ,如果能就直接顯示否則以附件的形式下載並儲存;
注意:指定在下載檔名中文情況下,必須先進行編碼;
JS
// iframe var downloadFileUrl = "http://localhost:3000" var elemIF = document.createElement("iframe"); elemIF.src = downloadFileUrl; elemIF.style.display = "none"; document.body.appendChild(elemIF); // a var a = document.createElement('a'); a.href = downloadFileUrl; a.click();
上述兩種方式僅僅就是傳送一個請求,主要依賴後端的支援;對不需要精確知道檔案下載的狀態,上面方式就能滿足下載;
大家可能有疑問,iframe 不是可以通過 onload 來捕獲載入的完成狀態 ?
先來看看 load 適用哪些物件?
load
W3C 對 load 定義
Type load Sync / Async Async Bubbles No Trusted Targets Window
,Document
,Element
適用物件:window,Document,Element 那麼對於我們下載的檔案並在其範圍;
如果需要捕獲檔案下載的進度以及檔案下載完成的狀態,需要使用下面的方式;
XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onprogress = function (event) {
console.log(Math.round(event.loaded / event.total * 100) + "%");
};
xhr.responseType = 'arraybuffer';
xhr.addEventListener('readystatechange', function (event) {
if (xhr.status === 200 && xhr.readyState === 4) {
// 獲取響應頭主要獲取附件名稱
var contentDisposition = xhr.getResponseHeader('content-disposition');
// 獲取型別型別和編碼
var contentType = xhr.getResponseHeader('content-type');
// 構造blob物件,具體看頭部提供的連結地址
var blob = new Blob([xhr.response], {
type: contentType
});
var url = window.URL.createObjectURL(blob);
// 獲取資料夾名
var regex = /filename=[^;]*/;
var matchs = contentDisposition.match(regex);
if (matchs) {
filename = decodeURIComponent(matchs[0].split("=")[1]);
} else {
filename = +Date.now() + ".doc";
}
var a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
// dosomething
}
})
xhr.send();
上述對比第一種方式,通過 onprogress
捕獲下載進度(介面通過顯示進度條來提升體驗);通過 readystatechange
監聽下載完後並可以做其它的事情;
注意: 必須指定 responseType 型別,可以是arraybuffer 或 blob 否則會出現錯誤問題 比如 zip,pdf檔案下載之後打不開提示錯誤的格式; .doc,.excel檔案內容亂碼等;