比如前后端约定,下载成功返回二进制流,下载失败返回对象{code: 0, msg: ‘失败原因’}
问题:当下载文件时,axios配置responseType: ‘blob’,此时后台返回的数据会被强制转为blob类型;如果后台返回失败对象,前端也无法得知,如果按正常处理会得到名为undefined的文件。
解决:在try代码块里面尝试将axios已经转成blob格式的res转回json格式,如果不报错说明服务端返回的是对象,表示下载失败;如果进入catch说明返回的是二进制流。
主要技术点:FileReader window.URL.createObjectURL Blob a标签实现下载
axios配置:
axios({
method: ‘post’,
baseURL: ‘’,
url: ‘’l,
timeout: 3000,
headers: {},
data: options.method.toLowerCase() !== 'get' ? options.data : undefined,
responseType: 'blob'
}).then(
res => {
const data = res.data
// 有可能下载失败,比如返回{code: 0},但设置了responseType: 'blob',axios会把data强制转为blob,导致下载undefined.excel(后缀取决于文件类型,这里只是举例)
// 解决:将已转为blob类型的data转回json格式,判断是否下载成功
const r = new FileReader()
r.onload = function () {
// 如果JSON.parse(this.result)不报错,说明this.result是json字符串,则可以推测是下载报错情况下返回的对象,类似于{code: 0}
// 如果JSON.parse(this.result)报错,说明是下载成功,返回的二进制流,则进入catch进行后续处理
try {
const resData = JSON.parse(this.result) // this.result为FileReader获取blob数据转换为json后的数据,即后台返回的原始数据
// 如果执行到这里,说明下载报错了,进行后续处理
} catch (err) {
// 下载正常处理
let fileName = res.headers['content-disposition']
// 获取文件名
if (fileName && fileName.length >= 2) {
fileName = fileName.split('=')[1]
}
fileName = decodeURIComponent(fileName)
// 兼容ie11
if (window.navigator.msSaveOrOpenBlob) {
try {
const blobObject = new Blob([data])
window.navigator.msSaveOrOpenBlob(blobObject, fileName)
} catch (e) {
console.log(e)
}
return
}
// a标签实现下载
let url = window.URL.createObjectURL(new Blob([data]))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
resolve(fileName)
}
}
r.readAsText(data) // FileReader的API
}).catch(res => {
console.log(res)
})