本文详解前端如何接收后端返回的二进制流文件并正确下载。重点解决因responseType设置不当导致的文件乱码问题,介绍通过axios设置arraybuffer或blob类型的方法。同时提供判断接口返回内容为正常文件或错误JSON字符串的逻辑,实现智能下载与异常提示,并对比React fetch与axios的实现差异。
下载文件时,文件名通常有两种生成策略:
- 采用固定前缀结合当前时间戳的方式,这是最常见的做法。
- 由后端在HTTP响应头中指定文件名,前端解析该头部信息作为下载文件名。
使用react的同学注意了,fetch难设置乱码转码,建议使用axios,用fetch亲自尝试失败+10086次,下载下来的xlsx全是乱码
前端下载文件通常有两种途径:一是后端提供HTTP下载链接,前端通过window.open或创建带有href属性的a标签触发下载;二是后端直接返回文件二进制内容,前端进行转换后触发下载。
第一种方式实现简单,此处不再赘述。本文将重点阐述第二种方式的具体实现步骤。
涉及Blob对象与ajax请求(如axios)。根据MDN文档,Blob对象用于表示不可变的原始数据类文件对象,其数据格式不一定局限于JavaScript原生类型。
Blob对象表示一个不可变、原始数据的类文件对象。Blob 表示的不一定是JavaScript原生格式的数据
具体实现步骤如下:
axios({
method: 'post',
url: '/export',
})
.then(res => {
// 假设 data 是返回来的二进制数据
const data = res.data
const url = window.URL.createObjectURL(new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', 'excel.xlsx')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})打开下载的文件,检查文件内容是否正确。

发现文件内容显示为一堆乱码。
这表明代码中存在未处理的问题。
经排查,问题出在axios请求的responseType参数上。该参数用于指定服务器响应的数据类型。由于后端返回的是二进制数据,前端必须将responseType设置为arraybuffer(若后端约定返回blob类型,则应设置为'blob')。
axios({
method: 'post',
url: '/export',
responseType: 'arraybuffer',
// responseType: 'blob'
})
.then(res => {
// 假设 data 是返回来的二进制数据
const data = res.data
const url = window.URL.createObjectURL(new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', 'excel.xlsx')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})
调整参数后再次测试,文件可以正常打开,内容显示正常,不再出现乱码。
根据后端接口返回的具体内容来决定是否执行下载操作。作者的项目中大量页面具备文件下载功能,且需求较为复杂。
具体业务需求如下:
若下载的数据量符合规定,则正常执行下载(各页面限制的数据量不同,故不能在前端硬编码限制)。若文件体积过大,后端会返回特定JSON格式:{ code: 199999, msg: '文件过大,请重新设置查询项', data: null },前端需据此进行错误提示。分析可知,下载接口的响应数据类型为arraybuffer。无论后端返回的是二进制文件还是JSON字符串,前端接收到的原始数据均为arraybuffer。因此,需对arraybuffer内容进行解析判断:将其转换为字符串后,检查是否包含code: 199999。若包含,则弹出错误提示;否则,视为正常文件并执行下载。具体代码实现如下:
axios.interceptors.response.use(response => {
const res = response.data
// 判断响应数据类型是否 ArrayBuffer,true 则是下载文件接口,false 则是正常接口
if (res instanceof ArrayBuffer) {
const utf8decoder = new TextDecoder()
const u8arr = new Uint8Array(res)
// 将二进制数据转为字符串
const temp = utf8decoder.decode(u8arr)
if (temp.includes('{code:199999')) {
Message({
// 字符串转为 JSON 对象
message: JSON.parse(temp).msg,
type: 'error',
duration: 5000,
})
return Promise.reject()
}
}
// 正常类型接口,省略代码...
return res
}, (error) => {
// 省略代码...
return Promise.reject(error)
})React环境下使用fetch的实现方案:
const qryurl = `/offapi/liveaum/exportExcelData`;
fetch(qryurl, {
method: 'POST',
credentials: 'include',
headers: { Accept: 'application/json', 'Content-Type': 'application/json;charset=UTF-8' },
body: JSON.stringify(params),
}).then(response => {
if (response.ok) {
let downloadFileName = decodeURIComponent(response.headers.get('filename'));
this.setState({ downloadFileName, downModalShow: true, iconLoading: false });
response.blob().then(blob => {
downBlob = blob;
});
}
}).catch(function(err) {
console.log(err);
downBlob = null;
message.warning('暂未查询到数据');
this.setState({ iconLoading: false })
});
// 导出文件
handleOk = () => {
const link = document.createElement('a');
link.style.display = 'none';
link.href = URL.createObjectURL(downBlob);
link.download = `${this.state.downloadFileName}.xls`;
document.body.appendChild(link);
link.click();
URL.revokeObjectURL(link.href);
document.body.removeChild(link);
message.success('下载成功');
this.onModalclose();
};至此,关于JS处理后端返回二进制流文件下载及乱码解决的方法已介绍完毕。更多相关js二进制文件下载导出内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!