[JavaScript] 文件下載

一、文件下載

業(yè)務(wù)中常用的下載類(lèi)型有多種,其接口的responseType 也不同:
xlsx類(lèi)型是application/vnd.msexcel,
zip類(lèi)型application/x-zip-compressed,
其他類(lèi)型application/octet-stream
在前端接受此數(shù)據(jù)進(jìn)行處理時(shí),可以 統(tǒng)一 轉(zhuǎn)為Blob 數(shù)據(jù),然后再生成文件下載。

實(shí)現(xiàn)如下:

const filename = response.headers['content-disposition'].match(
      /filename=(.*)/
)[1]
// 首先要?jiǎng)?chuàng)建一個(gè) Blob 對(duì)象(表示不可變、原始數(shù)據(jù)的類(lèi)文件對(duì)象)
const blob = new Blob([response.data], {type: 'application/zip'});
// or const blob = new File([response.data], fileName);

if (typeof window.navigator.msSaveBlob !== 'undefined') {
    // 兼容IE,window.navigator.msSaveBlob:以本地方式保存文件
    window.navigator.msSaveBlob(blob, decodeURI(filename))
} else {
    let elink = document.createElement("a"); // 創(chuàng)建一個(gè)<a>標(biāo)簽
    elink.style.display = "none"; // 隱藏標(biāo)簽
    elink.href = window.URL.createObjectURL(blob); // 配置href,指向本地文件的內(nèi)存地址
    elink.download = filename;
    elink.click();
    URL.revokeObjectURL(elink.href); // 釋放URL 對(duì)象
    document.body.removeChild(elink); // 移除<a>標(biāo)簽
}

幾個(gè)相關(guān)的小知識(shí):
1、Content-Type: application/octet-stream 等告訴客戶(hù)端這是一個(gè)二進(jìn)制文件,content-disposition 字段告訴客戶(hù)端一個(gè)需要下載的附件并告訴瀏覽器該附件默認(rèn)的文件名。

2、content-disposition字段正常情況下能在瀏覽器中看到, 但是js獲取不到。 原因?yàn)椋耗J(rèn)情況下,header 只有七種 simple response headers (簡(jiǎn)單響應(yīng)首部)可以暴露給外部。

Cache-Control
Content-Language
Content-Length
Content-Type
Expires
Last-Modified
Pragma

如果想讀取其值 可以如下進(jìn)行設(shè)置:

response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("content-disposition", "attachment; filename=" + filename);

3、如果直接在瀏覽器中打開(kāi)Content-Type: application/octet-stream 等二進(jìn)制類(lèi)型的文件時(shí),會(huì)直接下載, 原因是因?yàn)闉g覽器由于無(wú)法識(shí)別流數(shù)據(jù)。如果是瀏覽器可識(shí)別的格式,如 xml, image 等則不會(huì)下載,會(huì)以預(yù)覽的形式存在。

4、ajax 本身無(wú)法觸發(fā)瀏覽器的下載功能, 它的 response 會(huì)交由 JavaScript 處理,使用 ajax 下載完成后,response 以字符串的形式存儲(chǔ)在內(nèi)存中,所以可以在瀏覽器中preview中看到返回?cái)?shù)據(jù),但是卻不可以下載。
但瀏覽器的 GET 請(qǐng)求(主要以 frame 加載, a 標(biāo)簽點(diǎn)擊觸發(fā))或 POST請(qǐng)求(以 form 的形式存在)是可以下載文件的,因?yàn)檫@是瀏覽器的內(nèi)置事件,下載的 response 會(huì)交由瀏覽器自己處理,瀏覽器如果識(shí)別到是二進(jìn)制流數(shù)據(jù)則下載,上面文件下載也是使用的瀏覽器的此下載功能實(shí)現(xiàn)。

二、基礎(chǔ)知識(shí)

1、 Blob

Blob對(duì)象表示一個(gè)不可變、原始數(shù)據(jù)的類(lèi)文件對(duì)象。它的數(shù)據(jù)可以按文本或二進(jìn)制的格式進(jìn)行讀取,也可以轉(zhuǎn)換成 ReadableStream 來(lái)用于數(shù)據(jù)操作。 Blob 表示的不一定是JavaScript原生格式的數(shù)據(jù)。

  • 其他非blob對(duì)象和數(shù)據(jù) 構(gòu)造Blob
   const data = { hello: 'world' };
   const blob = new Blob([JSON.stringify(data, null, 2)], {type : 'application/json'});
   console.log(blob)
blob 打印.png
  • Blob 對(duì)象的屬性
    size:Blob對(duì)象中所包含數(shù)據(jù)的大?。ㄗ止?jié));
    type: string,表明該 Blob 對(duì)象所包含數(shù)據(jù)的 MIME 類(lèi)型。如果類(lèi)型未知,則該值為空字符串。 看上圖 size 為22, type為application/json
  • Blob對(duì)象轉(zhuǎn)為其他格式
    即從Blob對(duì)象中讀出其包含的數(shù)據(jù)。
    Blob.text(): 返回一個(gè)promise且包含blob所有內(nèi)容的UTF-8格式的 USVString。
  const data = { hello: 'world' };
   const blob = new Blob([JSON.stringify(data, null, 2)], {type : 'application/json'});
   blob.text().then( text => console.log(text))

image.png

注意: text為string類(lèi)型。
除此之外還有Blob.arrayBuffer()Blob.stream()

  • responseType屬性設(shè)置為“blob”
    將二進(jìn)制文件讀取為blob類(lèi)型的數(shù)據(jù)

2、File API

File 接口基于Blob,繼承了 blob 的功能并將其擴(kuò)展使其支持用戶(hù)系統(tǒng)上的文件, 提供有關(guān)文件的信息,并允許網(wǎng)頁(yè)中的 JavaScript 訪(fǎng)問(wèn)其內(nèi)容

  • File()
    返回一個(gè)新構(gòu)建的文件對(duì)象(File)

更多File文件內(nèi)容參見(jiàn)我的另一篇文檔由淺入深了解文件操作

三、 其他方法

獲取一張圖片的寬高

export default function getUploadImgSize(file) {
  return new Promise(resolve => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = function(e) {
      const result = e.target.result
      const img = new Image()
      img.src = result
      img.onload = function() {
        resolve({
          width: img.width,
          height: img.height,
        })
      }
    }
  })
}

參考資料

1、MDN - Blob

hi~ 點(diǎn)贊了么~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容