原理:前端將二進(jìn)制文件做轉(zhuǎn)換
實(shí)現(xiàn)下載:請(qǐng)求后端接口->接收后端返回的二進(jìn)制流(通過(guò)二進(jìn)制流(Blob
)下載, 把后端返回的二進(jìn)制文件放在 Blob 里面)->再通過(guò)file-saver
插件保存
需求背景
業(yè)務(wù):下載模板文件
頁(yè)面上使用:
<span @click="downloadFile">下載當(dāng)前文件模板</span>
downloadFile() {
let dowloadUrl
if (this.dowloadUrl) {
dowloadUrl = this.dowloadUrl
}else if (this.fullPathUrl) {
dowloadUrl = this.fullPathUrl
}
downloadGet(dowloadUrl, `${this.fileName}.csv`, {})
},
保存文件:
import { saveAs } from 'file-saver'
發(fā)起請(qǐng)求通用方法(更改 axios 的 responseType):
本次業(yè)務(wù)需求中,直接使用 以下form標(biāo)簽形式下載(瀏覽器直接解析直接下載)會(huì)有文件訪問(wèn)權(quán)限問(wèn)題,所以轉(zhuǎn)換為發(fā)起axios請(qǐng)求接收二進(jìn)制流的方式。
<!-- <form v-show="false" id="templateForm" :action="templateUrl" method="get" /> -->
(post請(qǐng)求僅供參考,本次業(yè)務(wù)需求中沒(méi)有用到)
// 通用下載方法,blob形式--【post請(qǐng)求】
export function download(url, params, filename, config) {
downloadLoadingInstance = Loading.service({
text: '正在下載數(shù)據(jù),請(qǐng)稍候',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
return service
.post(url, params, {
transformRequest: [
(params) => {
return tansParams(params)
}
],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob', // 指定響應(yīng)類型為二進(jìn)制數(shù)據(jù)
...config
})
.then(async(data) => {
const isLogin = await blobValidate(data)
if (isLogin) {
const blob = new Blob([data])
saveAs(blob, filename)
} else {
const resText = await data.text()
const rspObj = JSON.parse(resText)
const errMsg =
errorCode[rspObj.code] || rspObj.msg || errorCode['default']
Message.error(errMsg)
}
downloadLoadingInstance.close()
})
.catch((r) => {
console.error(r)
Message.error('下載文件出現(xiàn)錯(cuò)誤,請(qǐng)聯(lián)系管理員!')
downloadLoadingInstance.close()
})
}
本次業(yè)務(wù)需求中,后端接口定義的get請(qǐng)求,所以前端發(fā)起axios-get請(qǐng)求:
// 通用下載方法,blob形式--【get請(qǐng)求】
export function downloadGet(url, filename, config) {
downloadLoadingInstance = Loading.service({
text: '正在下載數(shù)據(jù),請(qǐng)稍候',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
return service
.get(url, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob',// 指定響應(yīng)類型為二進(jìn)制數(shù)據(jù)
...config
})
.then(async(data) => {
const isLogin = await blobValidate(data)
if (isLogin) {
const blob = new Blob([data])
saveAs(blob, filename)
} else {
const resText = await data.text()
const rspObj = JSON.parse(resText)
const errMsg =
errorCode[rspObj.code] || rspObj.msg || errorCode['default']
Message.error(errMsg)
}
downloadLoadingInstance.close()
})
.catch((r) => {
console.error(r)
Message.error('下載文件出現(xiàn)錯(cuò)誤,請(qǐng)聯(lián)系管理員!')
downloadLoadingInstance.close()
})
}
封裝的方法:
/**
* 參數(shù)處理
* @param {*} params 參數(shù)
*/
export function tansParams(params) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName]
var part = encodeURIComponent(propName) + '='
// if (value !== null && value !== "" && typeof (value) !== "undefined") {
if (value !== null && typeof (value) !== 'undefined') {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && value[key] !== '' && typeof (value[key]) !== 'undefined') {
const params = propName + '[' + key + ']'
var subPart = encodeURIComponent(params) + '='
result += subPart + encodeURIComponent(value[key]) + '&'
}
}
} else {
result += part + encodeURIComponent(value) + '&'
}
}
}
return result
}
// 驗(yàn)證是否為blob格式
export async function blobValidate(data) {
try {
const text = await data.text()
JSON.parse(text)
return false
} catch (error) {
return true
}
}
// errorCode.js:
export default {
'401': '認(rèn)證失敗,無(wú)法訪問(wèn)系統(tǒng)資源',
'403': '當(dāng)前操作沒(méi)有權(quán)限',
'404': '訪問(wèn)資源不存在',
'default': '系統(tǒng)未知錯(cuò)誤,請(qǐng)反饋給管理員'
}
點(diǎn)擊"下載"按鈕:
相關(guān)技術(shù)
Blob
概念: Blob 對(duì)象表示一個(gè)不可變的, 原始數(shù)據(jù)的類文件對(duì)象,它的數(shù)據(jù)可以按文本或二進(jìn)制格式進(jìn)行讀取。
Blob 構(gòu)造函數(shù)
const aBlob = new Blob(array, option)
第一個(gè)參數(shù)是一個(gè)類數(shù)組, 必填
第二個(gè)參數(shù)非必填有兩個(gè)屬性: type, 表示MIME類型, 默認(rèn)值是’'。還有一個(gè)是endings 表示 /n 換行符如何被寫(xiě)入,默認(rèn)值是’transparent’保持不變, 還有’native’按照宿主機(jī)的換行符
總結(jié)
前端實(shí)現(xiàn)文件的下載主要有兩種方式:(1)直接打開(kāi)下載鏈接(通過(guò)瀏覽器解析方式直接下載)
;(2)通過(guò) Blob 對(duì)二進(jìn)制流文件下載
。實(shí)際用那種方法可以看后端的返回值和請(qǐng)求方式文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-697043.html
其他:
根據(jù)返回值構(gòu)造 Blob 函數(shù)并轉(zhuǎn)換成 URL ,動(dòng)態(tài)創(chuàng)建 a 標(biāo)簽打開(kāi) URL參考:
https://huaweicloud.csdn.net/63a55dc4b878a545459452ae.html文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-697043.html
到了這里,關(guān)于通過(guò) Blob 對(duì)二進(jìn)制流文件下載實(shí)現(xiàn)文件保存下載的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!