背景:
通过axios下载文件,正常情况下后端返回内容blob,前端接收并导出文件。但有时候,后端业务逻辑需要提示错误,于是返回json,但前端预期接收的是blob,所以导出去的文件内容是json字符串。
原因:
axios请求头配置了响应格式 responseType: 'blob'
const service = axios.create({
baseURL: '/'
})
// 导出用户列表
export function exportUserList(data){
return request({
url: '/admin/accelerate/duration/download',
method: 'post',
responseType: 'blob', // 指定响应内容为blob
data
})
}
解决方法:
在axios响应拦截器中,判断请求的响应类型。若预期返回blob但实际返回json,则将blob转成json字符串,然后进行错误提示。
// blob转字符串
export const blobTojsonstr = (blob) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.onerror = (e) => reject(e.target.error);
reader.readAsText(blob);
});
}
import { Notification } from 'element-ui'
// HTTP response 拦截
service.interceptors.response.use(
async (res) => {
const status = res.status
const responseType = res.config.responseType // 预期响应数据类型
const contentType = res.headers['content-type'] // 真实响应数据类型
let resData = null,
isBlob = ['arraybuffer', 'blob'].includes(responseType)
if (!isBlob) {
// 预期是非文件,即json
resData = res.data
} else {
// 预期是文件
if (contentType.indexOf('application/json') > -1) {
// 下载接口异常:Blob转Json后解密
isBlob = false
try {
const content = await blobTojsonstr(res.data)
resData = JSON.parse(JSON.parse(content).data)
} catch (error) {
resData = res.data
}
} else {
resData = res.data
}
}
// 不正确的状态码进行统一处理
if (!isBlob && (status !== 200 || resData.code !== 0)) {
const errMsg = resData.msg
Notification.error({
title: errMsg
})
return Promise.reject(new Error(errMsg))
}
return resData
},
(error) => {
return Promise.reject(new Error(error))
}
)
效果:
正常情况下,后端返回blob,axios接收blob并导出文件。
异常情况下,后端返回json,axios接收blob后转成json,根据错误码code提示错误。