如何用 JavaScript 下載檔案

來源:互聯網
上載者:User

標籤:res   javascrip   服務   沒有   trigger   訪問   with   等等   檔案名稱   

簡介

我們知道,下載檔案是一個非常常見的需求,但由於瀏覽器的安全性原則的限制,我們通常只能通過一個額外的頁面,訪問某個檔案的 url 來實現下載功能,但是這種使用者體驗非常不好。
幸好,HTML 5 裡面為 <a> 標籤添加了一個 download 的屬性,我們可以輕易的利用它來實現下載功能,再也不需要用以前的笨辦法了。

原理

我們先看看 download 的使用方法:

<a href="http://somehost/somefile.zip" download="filename.zip">Download file</a>

看看上面的代碼,只要為 <a> 標籤添加 download 屬性,我們點擊這個連結的時候就會自動下載檔案了~
順便說下,download 的屬性值是可選的,它用來指定下載檔案的檔案名稱。像上面的例子中,我們下載到本地的檔案名稱就會是 filename.zip 拉,如果不指定的話,它就會是 somefile.zip 這個名字拉!

看到這裡,你可能會說,坑爹啊,這明明是用 HTML 5 的新特性來實現下載檔案嘛,說好的用 JavaScript 下載檔案呢?

事實上,用 JavaScript 來下載檔案也是利用這一特性來實現的,我們的 JavaScript 代碼不外乎就是:

  • 用 JavaScript 建立一個隱藏的 <a> 標籤
  • 設定它的 href 屬性
  • 設定它的 download 屬性
  • 用 JavaScript 來觸發這個它的 click 事件

翻譯成 JavaScript 代碼就是:

var a = document.createElement(‘a‘);var url = window.URL.createObjectURL(blob);var filename = ‘what-you-want.txt‘;a.href = url;a.download = filename;a.click();window.URL.revokeObjectURL(url);

好拉,是不是看到有個陌生的東東呢?

window.URL

window.URL 裡面有兩個方法:

  • createObjectURL 用 blob 對象來建立一個 object URL(它是一個 DOMString),我們可以用這個 object URL 來表示某個 blob 對象,這個 object URL 可以用在 href 和 src 之類的屬性上。
  • revokeObjectURL 釋放由 createObjectURL 建立的 object URL,當該 object URL 不需要的時候,我們要主動調用這個方法來擷取最佳效能和記憶體使用量。

知道了這兩個方法之後,我們再回去看看上面的例子就很容易理解了吧!只是用 blob 對象來建立一條 URL,然後讓 <a> 標籤引用該 URL,然後觸發個點擊事件,就可以下載檔案了!

那麼問題來了,blob 對象哪裡來?

Blob 對象

Blob 全稱是 Binary large object,它表示一個類檔案對象,可以用它來表示一個檔案。根據 MDN 上面的說法,File API 也是基於 blob 來實現的。

由於本文的主題是講 JavaScript 下載檔案,那我們構建 blob 的方式就是通過伺服器返回的檔案來建立 blob 拉!
而最簡單的方式就是用 fetch API 了,我們可以整合上面的例子:

fetch(‘http://somehost/somefile.zip‘).then(res => res.blob().then(blob => { var a = document.createElement(‘a‘); var url = window.URL.createObjectURL(blob); var filename = ‘myfile.zip‘; a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url);}))

很簡單對吧!

你可能會問,何必這麼麻煩呢?直接寫成下面這樣不就好了:

<a href="http://somehost/somefile.zip" download="myfile.zip">Download file</a>

嗯,對於這種寫法,我只能說,你做的太正確了!如果你要下載的是已經存在伺服器上面的靜態檔案的話,那麼寫成這樣是最方便的。瀏覽器會幫你處理整個下載過程,不需要你幹涉。如果你用 blob 的方式來下載檔案的話,會有下面這些限制的:

限制一:不同瀏覽器對 blob 對象有不同的限制

具體看看下面這個表格(出自 FileSaver.js):

Browser Constructs as Filenames Max Blob Size Dependencies
Firefox 20+ Blob Yes 800 MiB None
Firefox < 20 data: URI No n/a Blob.js
Chrome Blob Yes 500 MiB None
Chrome for Android Blob Yes 500 MiB None
Edge Blob Yes ? None
IE 10+ Blob Yes 600 MiB None
Opera 15+ Blob Yes 500 MiB None
Opera < 15 data: URI No n/a Blob.js
Safari 6.1+* Blob No ? None
Safari < 6 data: URI No n/a Blob.js
限制二:構建完 blob 對象後才會轉換成檔案

這一點限制對小檔案(幾十kb)可能沒什麼影響,但對稍微大一點的檔案影響就很大了。試想,使用者要下載一個 100mb 的檔案,如果他點擊了下載按鈕之後沒看到下載提示的話,他肯定會繼續按,等他按了幾次之後還沒看到下載提示時,他就會抱怨我們的網站,然後離開了。

然而事實上下載的的確確發生了,只是要等到下載完檔案之後才能構建 blob 對象,再轉化成檔案。而且,使用者再觸發多幾次下載就會造成一些資源上的浪費。

因此,如果是要下載大檔案的話,還是推薦直接建立一個 <a> 標籤拉~
寫 html 也好,寫 JavaScript 動態建立也好,用自己喜歡的方式去建立就好了。

為什麼要用 JavaScript 下載檔案

好拉,說了半天,其實我們一直說的都是:「不要用 JavaScript 下載檔案拉,限制多多,又不好用,直接用 html 就好拉,簡單方便又快捷」這個論調。
事實上也確實如此,但有些時候我們確實需要通過 JavaScript 來做一些處理。

許可權校正

有些時候,我們需要對下載做一些限制,最常見的就是許可權校正了,如檢查該使用者是否有下載的許可權,是否有高速下載的許可權等等。這時候,我們可以利用 JavaScript 做一些預先處理。如:

fetch(‘http://somehost/check-permission‘, options).then(res => { if (res.code === 0) { var a = document.createElement(‘a‘); var url = res.data.url; var filename = ‘myfile.zip‘; a.href = url; a.download = filename; a.click(); } else { alert(‘You have no permission to download the file!‘); }});

在這個例子裡面,我們沒有用 blob 來構建 URL,而是通過後端伺服器來計算出使用者的下載連結,然後再利用之前提到的動態建立 <a> 標籤的方式來實現下載,很簡單吧!

動態檔案

動態組建檔案然後返回給用戶端也是一個很常見的需求,譬如我們有時候需要做匯出資料的功能,把資料庫中的某些資料匯出到 Excel 中,然後再返回用戶端。
這時候我們就不能簡單的指定 href 屬性,因為對應的 URL 並不存在。
我們只能通過 JavaScript 對伺服器發出一個請求,通知它去產生某個檔案,然後把對應的 URL 返回給用戶端。
有沒有感覺這個過程和上面「許可權校正」一節很像?肯定拉,因為我們只是對 URL 做了一些預先處理而已嘛~

注意事項

由於 download 屬性是 HTML 5 的新特性,因此它不支援舊版本的瀏覽器。

總結

HTML 5 新的 download 特性真的很好用,結合 JavaScript 的動態能力我們可以很方便的做出複雜的下載功能~

參考資料

https://github.com/eligrey/FileSaver.js/blob/master/FileSaver.js
https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
https://developer.mozilla.org/en-US/docs/Web/API/Blob
http://stackoverflow.com/questions/19327749/javascript-blob-filename-without-link
http://stackoverflow.com/questions/24501358/how-to-set-a-header-for-a-http-get-request-and-trigger-file-download
http://blog.bguiz.com/2014/07/03/file-download-with-http-request-header/

如何用 JavaScript 下載檔案

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.