一、文件下載
業(yè)務(wù)中常用的下載類(lèi)型有多種,其接口的responseType 也不同:
xlsx類(lèi)型是application/vnd.msexcel,
zip類(lèi)型application/x-zip-compressed,
其他類(lèi)型application/octet-stream
在前端接受此數(shù)據(jù)進(jìn)行處理時(shí),可以 統(tǒng)一 轉(zhuǎn)為Blob 數(shù)據(jù),然后再生成文件下載。
實(shí)現(xiàn)如下:
const filename = response.headers['content-disposition'].match(
/filename=(.*)/
)[1]
// 首先要?jiǎng)?chuàng)建一個(gè) Blob 對(duì)象(表示不可變、原始數(shù)據(jù)的類(lèi)文件對(duì)象)
const blob = new Blob([response.data], {type: 'application/zip'});
// or const blob = new File([response.data], fileName);
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// 兼容IE,window.navigator.msSaveBlob:以本地方式保存文件
window.navigator.msSaveBlob(blob, decodeURI(filename))
} else {
let elink = document.createElement("a"); // 創(chuàng)建一個(gè)<a>標(biāo)簽
elink.style.display = "none"; // 隱藏標(biāo)簽
elink.href = window.URL.createObjectURL(blob); // 配置href,指向本地文件的內(nèi)存地址
elink.download = filename;
elink.click();
URL.revokeObjectURL(elink.href); // 釋放URL 對(duì)象
document.body.removeChild(elink); // 移除<a>標(biāo)簽
}
幾個(gè)相關(guān)的小知識(shí):
1、Content-Type: application/octet-stream 等告訴客戶(hù)端這是一個(gè)二進(jìn)制文件,content-disposition 字段告訴客戶(hù)端一個(gè)需要下載的附件并告訴瀏覽器該附件默認(rèn)的文件名。
2、content-disposition字段正常情況下能在瀏覽器中看到, 但是js獲取不到。 原因?yàn)椋耗J(rèn)情況下,header 只有七種 simple response headers (簡(jiǎn)單響應(yīng)首部)可以暴露給外部。
Cache-Control
Content-Language
Content-Length
Content-Type
Expires
Last-Modified
Pragma
如果想讀取其值 可以如下進(jìn)行設(shè)置:
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("content-disposition", "attachment; filename=" + filename);
3、如果直接在瀏覽器中打開(kāi)Content-Type: application/octet-stream 等二進(jìn)制類(lèi)型的文件時(shí),會(huì)直接下載, 原因是因?yàn)闉g覽器由于無(wú)法識(shí)別流數(shù)據(jù)。如果是瀏覽器可識(shí)別的格式,如 xml, image 等則不會(huì)下載,會(huì)以預(yù)覽的形式存在。
4、ajax 本身無(wú)法觸發(fā)瀏覽器的下載功能, 它的 response 會(huì)交由 JavaScript 處理,使用 ajax 下載完成后,response 以字符串的形式存儲(chǔ)在內(nèi)存中,所以可以在瀏覽器中preview中看到返回?cái)?shù)據(jù),但是卻不可以下載。
但瀏覽器的 GET 請(qǐng)求(主要以 frame 加載, a 標(biāo)簽點(diǎn)擊觸發(fā))或 POST請(qǐng)求(以 form 的形式存在)是可以下載文件的,因?yàn)檫@是瀏覽器的內(nèi)置事件,下載的 response 會(huì)交由瀏覽器自己處理,瀏覽器如果識(shí)別到是二進(jìn)制流數(shù)據(jù)則下載,上面文件下載也是使用的瀏覽器的此下載功能實(shí)現(xiàn)。
二、基礎(chǔ)知識(shí)
1、 Blob
Blob對(duì)象表示一個(gè)不可變、原始數(shù)據(jù)的類(lèi)文件對(duì)象。它的數(shù)據(jù)可以按文本或二進(jìn)制的格式進(jìn)行讀取,也可以轉(zhuǎn)換成 ReadableStream 來(lái)用于數(shù)據(jù)操作。 Blob 表示的不一定是JavaScript原生格式的數(shù)據(jù)。
- 其他非blob對(duì)象和數(shù)據(jù) 構(gòu)造Blob
const data = { hello: 'world' };
const blob = new Blob([JSON.stringify(data, null, 2)], {type : 'application/json'});
console.log(blob)

- Blob 對(duì)象的屬性
size:Blob對(duì)象中所包含數(shù)據(jù)的大?。ㄗ止?jié));
type: string,表明該 Blob 對(duì)象所包含數(shù)據(jù)的 MIME 類(lèi)型。如果類(lèi)型未知,則該值為空字符串。 看上圖 size 為22, type為application/json - Blob對(duì)象轉(zhuǎn)為其他格式
即從Blob對(duì)象中讀出其包含的數(shù)據(jù)。
Blob.text(): 返回一個(gè)promise且包含blob所有內(nèi)容的UTF-8格式的USVString。
const data = { hello: 'world' };
const blob = new Blob([JSON.stringify(data, null, 2)], {type : 'application/json'});
blob.text().then( text => console.log(text))

注意: text為string類(lèi)型。
除此之外還有
Blob.arrayBuffer()、Blob.stream()
- responseType屬性設(shè)置為
“blob”
將二進(jìn)制文件讀取為blob類(lèi)型的數(shù)據(jù)
2、File API
File 接口基于Blob,繼承了 blob 的功能并將其擴(kuò)展使其支持用戶(hù)系統(tǒng)上的文件, 提供有關(guān)文件的信息,并允許網(wǎng)頁(yè)中的 JavaScript 訪(fǎng)問(wèn)其內(nèi)容
- File()
返回一個(gè)新構(gòu)建的文件對(duì)象(File)
更多File文件內(nèi)容參見(jiàn)我的另一篇文檔由淺入深了解文件操作
三、 其他方法
獲取一張圖片的寬高
export default function getUploadImgSize(file) {
return new Promise(resolve => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = function(e) {
const result = e.target.result
const img = new Image()
img.src = result
img.onload = function() {
resolve({
width: img.width,
height: img.height,
})
}
}
})
}
參考資料
hi~ 點(diǎn)贊了么~~