返回

技术实录 | 你是否有过axios下载的文件打不开的经历?

前端

现象
在使用axios库下载文件时,开发者经常会遇到这样的困惑:明明下载成功了,却无法打开。这时,仔细检查控制台,可能会发现错误信息中提示“Response has no content”或“Invalid file format”。

问题分析
造成此问题的根源在于axios库默认使用XMLHttpRequest对象来发送请求,而XMLHttpRequest对象有一个responseType属性,用来指定服务器响应的数据类型。当responseType设置为“arraybuffer”时,浏览器会将服务器响应的二进制数据存储在一个ArrayBuffer对象中,从而实现文件的下载。

然而,如果在开发过程中使用了mock.js这样的模拟数据库,则可能会导致这个问题。mock.js会重置XMLHttpRequest对象的responseType属性,使其变更为“json”。这将导致服务器响应的二进制数据被解析为JSON格式,从而导致文件损坏,无法打开。

解决方案
解决这个问题的步骤如下:

  1. 在使用mock.js时,需要在调用mock.setup()方法之前,对XMLHttpRequest对象的responseType属性进行备份,并在mock.setup()方法调用之后将其还原。

  2. 在使用axios下载文件时,需要明确指定responseType属性的值为“arraybuffer”,以确保服务器响应的二进制数据能够正确存储在ArrayBuffer对象中。

  3. 如果在使用axios下载文件时,遇到了“Response has no content”或“Invalid file format”等错误信息,则可以考虑是否使用了mock.js,并检查XMLHttpRequest对象的responseType属性是否被重置。

代码示例

// 备份XMLHttpRequest对象的responseType属性
const originalResponseType = XMLHttpRequest.prototype.responseType;

// 设置mock.js
mock.setup({
  timeout: 1000
});

// 使用axios下载文件
axios.get('/file.txt', {
  responseType: 'arraybuffer'
})
.then((response) => {
  // 将文件内容保存到本地
  const blob = new Blob([response.data], {type: 'text/plain'});
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'file.txt';
  a.click();
  URL.revokeObjectURL(url);
})
.catch((error) => {
  // 处理错误
  console.error(error);
});

// 还原XMLHttpRequest对象的responseType属性
XMLHttpRequest.prototype.responseType = originalResponseType;

总结
通过axios下载文件时,如果遇到文件无法打开的问题,可以考虑是否使用了mock.js,并检查XMLHttpRequest对象的responseType属性是否被重置。通过备份和还原responseType属性,可以确保axios能够正确下载文件。