起因就是要做一个数据导出的功能,今天提了个bug就是没有数据的时候后端数据code码返回的4001,前端没有判断直接做了下载处理,结果直接把错误信息下载了下来。
描述:当下载文件时,axios配置responseType: ‘blob’,此时后台返回的数据会被强制转为blob类型;如果后台返回代表失败的data,前端也无法得知,依然会下载得到名为undefined的文件。
解决:将blob转回json格式,通过code判断是否下载成功
主要技术点:FileReader
先上最后实现的完整代码:
axios({
baseURL: './',
url: `${this.uuurl}/system/export/index`,
method: 'get',
responseType: 'blob',
params: params,
data: {}
})
.then((res) => {
let _that = this;
const data = res.data;
// 有可能下载失败,返回{code: '500'},但responseType: 'blob'会把data强制转为blob,导致下载
// 解决:将已转为blob类型的data转回json格式,判断是否下载成功
let reader = new FileReader();
reader.readAsText(data, 'utf-8');
reader.onload = function () {
//本来是没有做这个try catch,但是其实不报错的时候下载的话是text/html,出错的话是application/json格式
try {
let jsondata = JSON.parse(reader.result)
if (jsondata && jsondata['code'] && jsondata['code'] != 200) {
// console.log('下载失败')
_that.$message.error(jsondata.err_msg);
// _that.dialogVisible = false;
}
}catch(err){
// console.log("可以去下载")
const content = res.data;
const blob = new Blob([content]);
const fileName = `用户数据_${new Date().toLocaleString()}` + '.xls';
if ('download' in document.createElement('a')) {
const link = document.createElement('a');
link.download = fileName;
link.style.display = 'none';
link.href = URL.createObjectURL(blob);
document.body.appendChild(link);
link.click();
URL.revokeObjectURL(link.href);
document.body.removeChild(link);
_that.$message.success('导出数据成功');
_that.dialogVisible = false;
} else {
_that.$message.error('导出数据失败');
}
}
};
})
.catch((error) => {
console.log(error);
});
以下是参考文章:
一、将blob返回值转为json数据
原文链接:https://blog.csdn.net/qq_41078029/article/details/98616815
let data = error.response.data;
if (error.request.responseType === 'blob') {
var reader = new FileReader();
reader.readAsText(data, 'utf-8');
reader.onload = function () {
data = JSON.parse(reader.result);
}
} else {
}
二、axios 的responseType 类型动态设置
原文链接:https://segmentfault.com/q/1010000014569305
我们不需要根据服务器返回的情况去随机设置responseType
1、我们要明白,我们在请求下载文件的api时候,可能给我们的返回值有两种情况:
- 直接给我们了我们想要的文件流
- 还有可能得到了JSON返回数据,让我们展现提示出信息或者被叫为错误信息
2、理解responseType
axios中这样描述的:responseType`表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
不过我经常用blob,其实用什么都无所谓,主要看在拿到返回值的时候如何处理。
3、处理返回值的不同情况
根据response.type返回内容的MIME TYPE 来判断是要下载文件,还是要去做一些JSON数据提示什么的操作。如果是JSON类型那就把Blob通过readAsText转为JSON格式。
这种方式通过测试IE10和IE10以上版本。
const API = axios.create({ baseURL: API_HOST }) API({ method: 'get', url: file.url, responseType: 'blob' }).then(response => { const type = response.type || null //relType你所下载的文件类型,这里是xlsx const relType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' if (type.includes(relType)) { /**做文件下载 */ return } if (type.includes('application/json')) { let reader = new FileReader() reader.onload = e => { if (e.target.readyState === 2) { let res = {} res = JSON.parse(e.target.result) console.info('back:: ', res) } } reader.readAsText(response) } })
三、下载文件时axios配置responseType: 'blob'判断下载是否成功(避免后台返回失败标识时依然下载undefined文件)
原文链接:https://blog.csdn.net/qq_37246828/article/details/90080614
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: '500'},但responseType: 'blob'会把data强制转为blob,导致下载undefined.excel // 解决:将已转为blob类型的data转回json格式,判断是否下载成功 let r = new FileReader() r.onload = function () { // 如果JSON.parse(this.result)不报错,说明this.result是json字符串,是下载报错情况的返回值,弹框提示 // 如果JSON.parse(this.result)报错,说明下载成功,进入catch try { let resData = JSON.parse(this.result) // this.result为FileReader获取blob数据转换为json后的数据,即后台返回的原始数据 if (resData && resData['code'] && resData['code'] === '500') { alert(‘下载失败’) } } 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 } 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) })