axios下载msword文件损坏

axios下载msword文件损坏

场景

项目中请求后端接口下载一个docx文件。
Response如下:
axios下载msword文件损坏_第1张图片

axios下载msword文件损坏_第2张图片
这时首先想到的是后端返回了二进制流,需要将流转换为Blob,生成downloadUrl,使用a标签下载。

Ctrl V 百度的代码:

axios({
  url: 'http://localhost:5000/download',
  method: 'POST',
  data: {
  	//...
  },
  responseType: 'blob', // 设置服务器响应的数据类型(必选)
}).then((response) => {
  const url = window.URL.createObjectURL(new Blob([response.data]));
  const link = document.createElement('a');
  link.href = url;
  link.download = 'file.docx';
  link.click();
});

然后愉快的测试,word下载成功。
继续打开文件,报错:很抱歉,无法打开xxx.docx,因为内容有问题。
axios下载msword文件损坏_第3张图片
内容有毛问题?点击确定:Word 在 xxx.docx 中发现无法读取的内容,是否恢复此文档的内容?如果您信任此文档的来源,请点击“是”
axios下载msword文件损坏_第4张图片
点击“是”还是无法打开,一定是后端的问题,过去撕逼。

然后被打脸:后端使用API文档工具测试,下载的文件可以正常打开。

继续回到座位百度,答案基本一样,观察细节尝试各种办法(可以直接跳转到最后查看成功的办法):

尝试办法1:

在创建Blob时指定type

let blob = new Blob([response.data], {type: 'application/msword'}) // 不行
let blob = new Blob([response.data], {type: 'application/octet-stream'}) // 不行

尝试方法2:

把正常的和不正常的docx文件后缀改为txt对比,发现虽然开头都是PK,但是我下载的文件中有大量的

而后端下载的文件内容虽然也看不懂(鱀咯暜==|eg?~€澐Y}跿憓之类的),但是没有

难道是编码问题?

再看看F12的response,返回的本来就是带的,忍住找后端的冲动。

开始从编码着手,可是项目默认请求的Content-Type就是 UTF-8 啊。
axios下载msword文件损坏_第5张图片
先试着请求时手动设置 Content-Type ,并没有解决。

axios({
  url: 'http://localhost:5000/download',
  method: 'POST',
  data: {
  	//...
  },
  headers: {
  	'content-type': 'application/json;charset=UTF-8'
  },
  responseType: 'blob', // 设置服务器响应的数据类型(必选)
}).then((response) => {
  //...
});

尝试方法3:

设置 responseType: 'arraybuffer',并没有解决

尝试方法4:

然后又百度到用 Base64 转码,尝试了,并没有解决。

尝试方法5(成功):

再次console打印接口返回的内容:
axios下载msword文件损坏_第6张图片
responseType: 'blob'设置成功了呀。

终于百度到一个靠谱的大神,多亏他回答问题是作了额外的说明(感激不尽)。

大神原话:

可以明显的看到,返回的response在的data 是一个blob Object。
createObjectURL 函数,接受的参数是blob 类型或者是File 类型。
所以说,我想创建的URL 对象只需要 如下代码
let url = URL.createObjectURL(response.data)
因为response.data 已经是一个blob Object 了,完全不需要再像 let url = window.URL.createObjectURL(new Blob([response.data]))载入

百度到的回答,都是用new Blob创建一个Blob,所以我完全没质疑过这个使用,并且没有查看过createObjectURL的使用方法。

于是调整代码,再次测试,word可以正常打开了。

axios({
  url: 'http://localhost:5000/download',
  method: 'POST',
  data: {
  	//...
  },
  responseType: 'blob', // 设置服务器响应的数据类型(必选)
}).then((response) => {
  const url = window.URL.createObjectURL(new Blob(response.data)); // 调整了这里
  const link = document.createElement('a');
  link.href = url;
  link.download = 'file.docx';
  link.click();
});

其他坑

有时由于封装 Axios 造成传参不规范,例如本项目中封装的请求,就把 responseType 包裹在 headers 中,导致开发人员工具中Request Header 中虽然显式了 responseType: blob 但是并没有没生效。
axios下载msword文件损坏_第7张图片

排查这个问题浪费了点时间,最终还是查看打印的 Axios 返回结果的 request.responseType为空才发现。
axios下载msword文件损坏_第8张图片

网上也有说使用mock的某些场景会把 responseType 默认修改为''

大神出处

papersnake 的回答

你可能感兴趣的:(过不去的坎)