原理:前端将二进制文件做转换
实现下载:请求后端接口->接收后端返回的二进制流(通过二进制流(Blob
)下载, 把后端返回的二进制文件放在 Blob 里面)->再通过file-saver
插件保存
业务:下载模板文件
<span @click="downloadFile">下载当前文件模板</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'
本次业务需求中,直接使用 以下form标签形式下载(浏览器直接解析直接下载)会有文件访问权限问题,所以转换为发起axios请求接收二进制流的方式。
<!-- <form v-show="false" id="templateForm" :action="templateUrl" method="get" /> -->
(post请求仅供参考,本次业务需求中没有用到)
// 通用下载方法,blob形式--【post请求】
export function download(url, params, filename, config) {
downloadLoadingInstance = Loading.service({
text: '正在下载数据,请稍候',
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', // 指定响应类型为二进制数据
...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('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close()
})
}
本次业务需求中,后端接口定义的get请求,所以前端发起axios-get请求:
// 通用下载方法,blob形式--【get请求】
export function downloadGet(url, filename, config) {
downloadLoadingInstance = Loading.service({
text: '正在下载数据,请稍候',
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',// 指定响应类型为二进制数据
...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('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close()
})
}
/**
* 参数处理
* @param {*} params 参数
*/
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
}
// 验证是否为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': '认证失败,无法访问系统资源',
'403': '当前操作没有权限',
'404': '访问资源不存在',
'default': '系统未知错误,请反馈给管理员'
}
Blob
概念: Blob 对象表示一个不可变的, 原始数据的类文件对象,它的数据可以按文本或二进制格式进行读取。
Blob 构造函数
const aBlob = new Blob(array, option)
第一个参数是一个类数组, 必填
第二个参数非必填有两个属性: type, 表示MIME类型, 默认值是’'。还有一个是endings 表示 /n 换行符如何被写入,默认值是’transparent’保持不变, 还有’native’按照宿主机的换行符
前端实现文件的下载主要有两种方式:(1)直接打开下载链接(通过浏览器解析方式直接下载)
;(2)通过 Blob 对二进制流文件下载
。实际用那种方法可以看后端的返回值和请求方式
根据返回值构造 Blob 函数并转换成 URL ,动态创建 a 标签打开 URL参考:
https://huaweicloud.csdn.net/63a55dc4b878a545459452ae.html