這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
前端涉及到的檔案下載還是很多應用場景的,那么前端檔案下載有多少種方式呢?每種方式有什么優缺點呢?下面就來一一介紹,
1. 使用 a 標簽下載
通過a標簽的download屬性來實作檔案下載,這種方式是最簡單的,也是我們比較常用的方式,先來看示例代碼:
<a href="http://www.baidu.com" download="baidu.html">下載</a>
就上面的這個示例,我們點擊下載,發現是跳轉到了百度的首頁,并沒有真的下載檔案,
因為a標簽下載只能下載同源的檔案;如果是跨域的檔案,比如圖片、音視頻等媒體檔案等都無法使用上面的a標簽方式下載,
上面的代碼是直接通過書寫a標簽來實作檔案下載;我們也可以通過js來實作,代碼如下:
const a = document.createElement('a')
a.href = 'http://www.baidu.com'
a.download = 'baidu.html'
a.click()
效果和上面的一樣,都是跳轉到百度的首頁,沒有下載檔案,
這里的重點是a標簽的download屬性,這個屬性是HTML5新增的,
它的作用是指定下載的檔案名,如果不指定,那么下載的檔案名就會根據請求內容的Content-Disposition來確定,如果沒有Content-Disposition,那么就會使用請求的URL的最后一部分作為檔案名,
2. 使用 window.open 下載
上面使用a標簽的案例也可以通過window.open來實作,效果是一樣的,代碼如下:
window.open('http://www.baidu.com', '_blank')
這里的_blank是指定用瀏覽器新視窗打開鏈接;如果不指定,那么就會在當前頁面打開,
同樣a標簽的download屬性也是可以使用的,代碼如下:
window.open('http://www.baidu.com', '_blank', 'download=baidu.html')
當然這種方式也是有缺陷的,對比于a標簽,window.open方式不能下載.html、.htm、.xml、.xhtml等檔案;因為這些檔案會被當成html檔案來處理,所以會直接在當前頁面打開,
同樣也不能下載跨域的檔案,這個是window.open 實作下載原理決定的,
3. 使用 location.? 下載
以下可以實作頁面跳轉的屬性,都可以實作檔案下載
3.1 location.href
// 這個方式和window.open是一樣的 location.href = 'http://www.baidu.com'
這種方式擁有window.open的所有缺陷,所以不推薦使用,這里只當作了解,所以不做過多的講解,
3.2 location.assign
location.assign('http://www.baidu.com')
3.3 location.replace
location.replace('http://www.baidu.com')
3.4 location.reload
location.reload('http://www.baidu.com')
location.reload是有點特殊的,它的作用是重新加載當前頁面,但是它也可以接受一個引數,這個引數就是要跳轉的頁面,所以也可以實作檔案下載,
當然同location.href一樣,這些方式的缺點都一樣,同時還有屬于每個屬性自身的特性,這里只當拓展知識,不做過多的講解,
4. XMLHttpRequest
這種方式就是我們常說的ajax下載,包括Axios、Fetch等,代碼如下:
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://www.baidu.com')
xhr.send()
xhr.onload = function () {
const blob = new Blob([xhr.response], { type: 'text/html' })
const a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = 'baidu.html'
a.click()
}
這里關于XMLHttpRequest相關的知識就不做展開了,只講和檔案下載相關的部分,
上面代碼主要的邏輯是當我們的請求成功后,我們會拿到回應體Response,這個Response就是我們要下載的內容,
然后我們把它轉換成Blob物件,通過URL.createObjectURL來創建一個URL,最后使用a標簽的download屬性來實作檔案下載,
5.1 Blob 物件
下面是MDN對Blob物件的定義:
Blob物件表示一個不可變、原始資料的類檔案物件,
Blob的資料可以按文本或二進制的格式進行讀取,也可以轉換成ReadableStream來用于資料操作,
Blob表示的不一定是JavaScript原生格式的資料,
File介面基于Blob,繼承了Blob的功能并將其擴展以支持用戶系統上的檔案,
Blob物件是html5新增的物件,它的作用是用來存盤二進制資料的,比如圖片、視頻、音頻等,它的使用方法如下:
/**
* @param {Array} array 二進制資料
* @param {Object} options 配置項
* @param {String} options.type 檔案型別,它代表了將會被放入到 blob 中的陣列內容的 MIME 型別,
* @param {String} options.endings 用于指定包含行結束符\n的字串如何被寫入,默認為transparent,表示不會修改行結束符,還可以指定為native,表示會將\n轉換為\r\n,
*/
const blob = new Blob([], { type: '' })
Tips:需要關注的是type屬性,默認情況下, Blob物件是沒有type屬性的,那么這個Blob就是一個無型別的Blob ,檔案不會損毀,但是無法被正常識別,
5.2 URL.createObjectURL
下面是MDN對 URL.createObjectURL方法的定義:
URL.createObjectURL()靜態方法會創建一個DOMString,其中包含一個表示引數中給出的物件的URL,
這個URL的生命周期和創建它的視窗中的document系結,
這個新的URL物件表示指定的File物件或Blob物件,
這個方法是用來創建一個URL的,它的作用是把一個Blob物件轉換成一個URL,這個URL可以用來下載檔案,也可以用來預覽檔案,代碼如下:
const url = URL.createObjectURL(blob)
這里需要注意的是,這個URL的生命周期和創建它的視窗中的document系結,
也就是說,當我們的document被銷毀后,這個URL就會失效,所以我們需要在合適的時機銷毀它,
代碼如下:
URL.revokeObjectURL(url)
回到我們剛才下載的問題,我們是通過Blob物件來解決,但是我們的type屬性是寫死的,如果在檔案型別是確定的情況下是沒問題的,
但是如果這個介面就是下載檔案的介面,檔案可能是各種型別的,我們應該怎么處理?
這里的沒有正確答案,第一個可以和介面提供者進行協商,協商方案是不確定的;第二就是通過Response的header來獲取檔案的type,也是我們要講的:
const type = response.headers['content-type']
const blob = new Blob([response.data], { type })
這里我們通過Response的header來獲取type,然后再創建Blob物件,這樣就可以正確的下載檔案了,
其實content-type也可能是application/octet-stream,這個時候我們就需要通過file-type來獲取檔案的type了,
下面的代碼是通過file-type來獲取檔案的type:
import {fileTypeFromStream} from 'file-type';
const type = await fileTypeFromStream(response.body);
const blob = new Blob([response.data], { type })
5. 總結
上面的方案這么多,其實最侄訓是落到a標簽上,所以不管是通過瀏覽器的內置行為進行下載,還是通過ajax進行下載,檔案下載的最侄訓是瀏覽器的行為,
本文轉載于:
https://juejin.cn/post/7254143696483991611
如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/557052.html
標籤:Html/Css
上一篇:基于分步表單的實踐探索
下一篇:返回列表

