網頁中直接下載 PDF 文件而不打開新的頁面加載 PDF 文件


我們知道 <a> 元素有 download 屬性,表示當前鏈接不是用來瀏覽的,而是用來下載的。它的值是一個字符串,表示用戶下載得到的文件名。可是對於 PDF 文件,瀏覽器默認打開一個新的頁面加載 PDF 文件,而不會直接下載該文件。

這時候我們需要將原來的用於下載的 url 進行轉換,轉換成一個 Blob 對象的 URL

一、用 Blob 對象來讀寫 PDF 文件

引入 Blob 對象,用 BlobBinary Large Object 二進制大型文件) 對象來讀寫 PDF 文件。

瀏覽器原生提供 Blob() 構造函數,用來生成實例對象。

new Blob(array [, options])

Blob 構造函數接受兩個參數。第一個參數是數組,成員是字符串或二進制對象,表示新生成的 Blob 實例對象的內容;第二個參數是可選的,是一個配置對象,目前只有一個屬性 type,它的值是一個字符串,表示數據的 MIME 類型,默認是空字符串。

let htmlFragment = ['<a id="a"><b id="b">hey!</b></a>'];
let myBlob = new Blob(htmlFragment, { type: 'text/html' });

上面代碼中,實例對象 myBlob 包含的是字符串。生成實例的時候,數據類型指定為 text/html

下面是另一個例子,Blob 保存 JSON 數據。

let obj = { hello: 'world' };
let blob = new Blob([JSON.stringify(obj)], { type: 'application/json' });

blob; // Blob {size: 17, type: "application/json"}

對於 MIME 類型,需要選擇適合二進制文件流的類型,而不是普通的文本類型:(MIME 類型)

瀏覽器通常使用 MIME 類型(而不是文件擴展名)來確定如何處理 URL,因此 Web 服務器在響應頭中添加正確的 MIME 類型非常重要。如果配置不正確,瀏覽器可能會曲解文件內容,網站將無法正常工作,並且下載的文件也會被錯誤處理。

還有一種很重要的 MIME 類型 application/octet-stream

這是應用程序文件的默認值。意思是 未知的應用程序文件 ,瀏覽器一般不會自動執行或詢問執行。瀏覽器會像對待 設置了 HTTPContent-Disposition 值為 attachment 的文件一樣來對待這類文件。

二、通過 URL.createObjectURL() 方法將 Blob 對象轉換成 url

URL.createObjectURL() 方法將流媒體文件生成一個 URL 字符串。這個字符串代表了 Blob 對象的 URL

該方法生成的 URL 就像下面的樣子(以 blob: 開頭的字符串)。

blob:http://localhost:3209/28c3a781-3492-4cff-82cc-2f72a0a7f245

至此我們就拿到了 Blob 對象的 URL


當我們拿到下載 PDF 文件的地址(url)和 PDF 文件名(name)后,先轉換成二進制文件流的 url,然后就可以下載該文件了。

handlePdfLink(url: string, name: string): void {
  fetch(url, {
    method: 'get'
  })
    .then(function (res) {
      if (res.status !== 200) {
        return res.json()
      }
      return res.arrayBuffer()
    })
    .then((blobRes) => {
      // 生成 Blob 對象,設置 type 等信息
      const e = new Blob([blobRes], {
        type: 'application/octet-stream'
      })
      // 將 Blob 對象轉為 url
      this.blobLink = window.URL.createObjectURL(e)

      this.downloadFile(this.blobLink, name)
    }).catch(err => {
      console.error(err)
    })
}

上面代碼中 arrayBuffer() 將產生一段二進制數據。Response.arrayBuffer()

arrayBuffer() 接受一個 Response 流, 並等待其讀取完成. 它返回一個 promise 實例, 並 resolve 一個 ArrayBuffer 對象。

然后將文件的MIME 類型設置為 application/octet-stream 讓瀏覽器不會自動執行或詢問執行,裝入 Blob 對象中進行讀取文件的數據內容。

再使用 URL.createObjectURL() 方法,針對 Blob 對象生成一個臨時 URL,以便於某些 API 使用。這個 URLblob: 開頭,表明對應一個 Blob 對象,協議頭后面是一個識別符,用來唯一對應內存里面的 Blob 對象。這一點與 data://URLURL 包含實際數據)和 file://URL(本地文件系統里面的文件)都不一樣。

最后我們添加 <a> 元素給它裝入下載地址 url 和下載文件名 name 來下載 PDF 文件。

downloadFile(url: string, name: string): void {
  if (url && url.trim()) {
    let a = document.createElement('a');
    a.href = url;
    a.download = name || '未命名文件';
    a.click();
    window.URL.revokeObjectURL(this.blobLink);
  } else {
    this.msg.remove();
    this.msg.error('文件下載路徑不能為空!');
  }
}

由於每次使用 URL.createObjectURL() 方法,都會在內存里面生成一個 URL 實例。如果不再需要該方法生成的 URL 字符串,為了節省內存,下載完成后可以使用 URL.revokeObjectURL() 方法釋放這個實例。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM