記一次關於pdf 下載需求變更到 pdf 線上預覽

Mmonologue發表於2021-10-27

背景:

  之前的需求是根據介面中提供的Blob資料實現PDF下載,已實現程式碼如下:

 1          const url = window.URL.createObjectURL(newBlob([response.data],{type: 'application/pdf'})
 2             const link = document.createElement('a')
 3             link.href = url
 4             let filename = response['headers']['content-disposition']?.split('filename=')[1]
 5             filename = decodeURI(filename)
 6             link.setAttribute('download', filename)
 7             document.body.appendChild(link)
 8             link.click()
 9             link.remove()
10             window.URL.revokeObjectURL(link.href)

思路就是: 獲取Blob資料 => 更改Blob型別 => 轉化為Blob URL => 生成a標籤 => 設定名稱 => 完成下載 => 去除a標籤 => 釋放Blob記憶體

新需求:   

 現 PRD 需要將直接下載更改為 瀏覽器線上預覽
 思路: 

  1.   利用a標籤的href屬性, 將接收到的Blob資料轉化為Base64資料格式,並將其型別更改為PDF,程式碼如下:
    1     let fileReader = new FileReader();
    2    let blobData = new Blob([response.data], {type: 'application/pdf'})
    3     fileReader.readAsDataURL(blobData);
    4     fileReader.onload = function(){
    5     base64Data = fileReader.result;
    6         console.log('base64資料', base64Data)
    7     }

    此方法可以實現需求,但是在新版谷歌瀏覽器被禁止,報錯如下

    Not allowed to navigate top frame to data URL:

    查詢結果如下: 

    Chrome 禁止從頁面開啟 Data URI 網址了,是出於安全考慮(釣魚方面)。
    
    單擊這個連結的話,會直接報錯,Not allowed to navigate top frame to data URL
    
    Chrome 的人做了統計,說從非 Data URI 頁面跳到 Data URI 頁面的情況只有不到萬分之五的概率,如果你的網站恰巧用到了這種在前端生成頁面的方式,可以嘗試遷移到後端來生成。

     

  2. 採用外掛來實現,由於使用的是react框架,所以採用了react-pdf外掛,此外掛地址如下: 
    https://www.npmjs.com/package/react-pdf

    文件說明較少,使用較簡單, 可以自定義樣式, 靈活性較高, 但樣式調整比較麻煩,而且有點點卡?

最終實現方法: 

   由於前兩種方法於PRD而言都有點瑕疵,最後恍然大悟,發現window.open一行程式碼可輕鬆解決,程式碼如下:

const url = window.URL.createObjectURL(newBlob([response.data],{type: 'application/pdf'})
window.open(url)

   之前只是記得window.open只能開啟url,沒想到Blob url也適用

Window.open()
Window 介面的 open() 方法,是用指定的名稱將指定的資源載入到瀏覽器上下文(視窗 window ,內嵌框架 iframe 或者標籤 tab )。如果沒有指定名稱,則一個新的視窗會被開啟並且指定的資源會被載入進這個視窗的瀏覽器上下文中。

語法

let windowObjectReference = window.open(strUrl, strWindowName, [strWindowFeatures]);
strUrl === 要在新開啟的視窗中載入的URL。

strWindowName === 新視窗的名稱。

strWindowFeatures === 一個可選引數,列出新視窗的特徵(大小,位置,滾動條等)作為一個DOMString。

   也是自己知識漏洞了. 這也是這偏隨筆的原因. 
   關於Blob Url:

Blob URL(參考W3C,官方名稱)或Object-URL(參考MDN和方法名稱)與Blob或File物件一起使用。

Blob URL只能由瀏覽器在內部生成。URL.createObjectURL()將建立一個特殊的Blob或File物件的引用,以後可以使用它來發布URL.revokeObjectURL()。這些URL只能在瀏覽器的單個例項中和同一個會話中(即頁面/文件的生命週期)在本地使用。


Blob URL / Object URL是一種偽協議,允許Blob和File物件用作影像,下載二進位制資料連結等的URL源。

例如,不能處理Image物件的原始位元組資料,因為它不知道如何處理它。它需要例如影像(二進位制資料)通過URL載入。這適用於任何需要URL作為源的東西。不用上傳二進位制資料,而是通過URL提供回來,最好使用額外的本地步驟來直接訪問資料而無需通過伺服器。

對於編碼為Base-64的字串的Data-URI也是更好的選擇。Data-URI的問題是每個char在JavaScript中佔用兩個位元組。最重要的是,由於Base-64編碼增加了33%。Blob是純粹的二進位制位元組陣列,它不像Data-URI那樣具有任何重要的開銷,這使得它們處理速度越來越快。
  1. 是一種偽協議
  2. 只能在瀏覽器內部生成
  3. 是Blob資料的唯一對映

  

相關文章