網頁中下載文件的相關總結

0. 概述

文件下載是web應用中很常見的場景,在瀏覽器中下載文件, 最基本的方式就是——在頁面內隱藏iframe, 而後將文件下載地址加載到iframe中, 從而觸發瀏覽器的下載行爲。 此外, html5引入a標籤的download屬性, 也是一種下載方式。html

<iframe src='download_url'></iframe>
<a download href='download_url'>下載</a>

下面針對下載地址的Response Header、瀏覽器兼容性, 以及一些特殊case, 作一些說明。html5

1. 怎樣的文件url才能觸發瀏覽器的下載行爲?

能觸發瀏覽器下載的url有兩類:web

  • response header中指定了Content-Dispositionattachment,它表示讓瀏覽器把響應體做爲附件下載到本地 (通常Content-Disposition還會指定filename, 下載的文件默認就是filename指定的名字)chrome

  • response header中指定了Content-Typeapplication/octet-stream(無類型) 或者 application/zip(下載zip包時)以及其它幾個不常見類型 (其中還有瀏覽器差別),其中 application/octet-stream表示http response爲二進制流(沒指定明確的type), 須要下載到本地, 由系統決定或者用戶手動指定打開方式。shell

關於application/octet-stream的狀況, 補充幾點canvas

  • 這種response, 因爲沒有明確的type, 若是做爲文件下載的話, 下載下來的文件將沒有文件名和拓展名(文件名直接取的url path的最後一坨)跨域

  • 若是不做爲文件下載, 好比已知response body是一張圖片, 能夠經過img標籤來顯示圖片瀏覽器

  • 下載下來的內容, 只是缺乏文件拓展名而已, 文件內容是完整的, 若是知道它實際的拓展名, 手動改了就能經過系統默認的程序打開, 不改拓展名的話也能經過指定應用程序的方式打開app

關於response header的Content-Type, 補充幾點curl

  • 首先要明確, Content-Type只是HTTP協議的部分, 不影響response body自身

  • Content-Type影響的是response的接收方(通常是瀏覽器), 對於瀏覽器而言, 它影響的是瀏覽器對響應體的處理方式. 好比指定爲application/zip, 瀏覽器就會用pdf閱讀器打開.

  • Content-Type之於瀏覽器, 就比如文件擴展名之於操做系統, 影響的默認行爲, 若是你指定了打開方式, 那麼Content-Type就不起做用了. 好比, 你在服務端對圖片地址設置Content-Type爲application/zip,但你在瀏覽器使用img標籤(至關於指定了打開方式)去加載, 照樣能正常加載圖片。

爲何上面說的「Content-Type」還有「文件拓展名」對於文件自身沒有影響?
這裏涉及到「文件格式協議」/「文件頭」等內容, 待補充...

2. <iframe src='' > 下載方式

只要知足上述「觸發瀏覽器自動下載」的url, 就能經過iframe的形式.
通常的用法是在html中隱藏iframe, 而後在業務代碼中經過設置iframe的src來實現下載.

3. <a href='' download>下載方式

download兼容性

主流瀏覽器對於的特殊狀況說明:

  • Safari只支持「能觸發瀏覽器下載」的url

  • Firefox也只支持「能觸發瀏覽器下載」的url, 此外還有一個須要注意的地方——點擊a標籤時, 會觸發「瀏覽器離開當前頁面」的行爲, 解決這個問題的方式是「再搭配一個iframe, 將a標籤的target指向這個iframe」,這樣就不會有頁面跳轉了

  • Chrome對於「不能觸發瀏覽器下載」的url, 也能夠經過這種方式下載。

4. 用哪一種方式

對於下載來源徹底由本身控制的業務場景(意味着Response Header是統一的), 推薦<iframe>的方式。

  • 瀏覽器兼容性好

  • 若是跟「下載」操做一塊兒還有一系列操做按鈕, 能夠統一代碼結構. (否則的話就「下載」操做按鈕是用的a標籤, 其它按鈕不是)

對於下載來源不受控制的場景, 則可選擇<a download>的方式

  • 在chrome下, 比iframe方式兼容的下載場景多

番外. 無可奈何, 花式的下載方式

構想這樣的場景, 對於Response Header中Content-Type爲image/png的圖片url,能怎樣下載呢?(這裏不考慮‘右鍵另存爲’)

對於Chrome瀏覽器,使用<a download>的方式能夠下載, 但其餘瀏覽器怎麼辦呢?

若是要強行下載這張圖片的話, 想了下, 也是有辦法的

  • 代碼中構造xhr請求該圖片地址, 以Blob的形式接收Response, 而後轉換成DataURL, 將DataURL的頭部設置爲image/octet-stream, 而後就可經過以上<iframe>的形式下載該DataURL了

  • 上面構造xhr請求的方式存在CORS問題, 若是不知足跨域條件, 簡單點的替換方案是使用img標籤加載圖片,而後畫到canvas上, 而後導出爲DataURL, 後續同上...

一些備註

  • 下載文件時, 在瀏覽器devTools的Network面板沒法查看下載請求的http相關信息, 若是你想觀察上面提到的Response Header中相關的信息, 可經過shell指令curl對下載地址發送HEAD請求, 以查看Response Header.

  • 關於各類case的驗證, 可本身簡單寫一個http服務, 設置不一樣的Response Header, 而後打開瀏覽器驗證。

  • 對於經過xhr去下載文件時跨域的問題, 有一個解決思路是, 本身寫一個代理服務, 代理服務負責在服務端下載文件, 並配置好跨域相關的信息, 而後xhr請求走代理服務進行下載。

相關文章
相關標籤/搜索