1. 程式人生 > >JS下載檔案常用的方式

JS下載檔案常用的方式

下載附件(image,doc,docx, excel,zip,pdf),應該是實際工作中經常遇到一個問題;這裡使用過幾種方式分享出來僅供參考; 初次寫可能存在問題,有問題望指出

​ 主要了解的幾個知識點:

先來介紹常用方式: 這裡下載.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檔案內容亂碼等;

來源:https://segmentfault.com/a/1190000017831033