如何使 pdf 文件在瀏覽器裡面直接下載而不是打開

前言

在做需求過程中我們大概率會遇到在瀏覽器中下載文件的需求,如果僅僅是這個要求的話很簡單,有如下兩種解決方式。

第一種是通過 window 對象的 open 方法進行操作,將文件 url 直接在瀏覽器中打開即可下載。

window.open('url')

第二種是通過 a 標籤,設置 href 為 url 值,點擊 a 標籤即可完成下載。

<a href='url' download='文件名'></a>

但是上面兩種文件下載方式都會存在一個問題,就是 pdf 文件會直接在瀏覽器中打開而不是直接下載,效果如下:

解決方案

這種需求的解決方式就是將PDF文件的 MIME type 改為 application/octet-stream 並加入 Content-Disposition:attachment header,原本的 pdf 文件 MIME type 為 application/pdf,瀏覽器識別到這個 type 之後會自動在瀏覽器打開,所以說我們在這裡修改 type 即可。

修改的方法有兩種,一種是在後端進行修改,上傳文件或者返迴文件的時候進行操作,但是絕大多數情況下文件都是存儲到 cdn 伺服器中的,後端也不方便對其進行操作,這個時候就需要前端來修改了。

處理程式碼如下:

/**
 * @deprecated 下載文件
 * @param {string} url 
 * @param {string} filename
 */
handleFileDownload = (url, filename) => {
  // 創建 a 標籤
  let a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
}

/**
 * @deprecated 處理 pdf url,使其不在瀏覽器打開
 * @param {string} url
 */
handlePdfLink = (url, filename) => {
  fetch(url, {
    method: 'get',
    responseType: 'arraybuffer',
  })
    .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',
        'Content-Disposition':'attachment'
      })
      // 將 Blob 對象轉為 url
      const link = window.URL.createObjectURL(e)
      handleFileDownload(link, filename)
    }).catch(err => {
      console.error(err)
    })
}

這樣修改修改程式碼的話就可以實現在瀏覽器中下載。效果如下