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

背景:

  之前的需求是根據介面中提供的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     }

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

    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數據的唯一映射

  

Tags: