实现从后端获取二进制数据并下载,以及乱码/打不开的问题 您所在的位置:网站首页 excel导入二进制文件 实现从后端获取二进制数据并下载,以及乱码/打不开的问题

实现从后端获取二进制数据并下载,以及乱码/打不开的问题

2023-12-20 18:33| 来源: 网络整理| 查看: 265

在工作中遇到一个关于文件下载的问题。 场景:从后端请求到一段二进制数据,点击按钮的时候下载。 一开始下载的文件呐,不是打不开,就是打开了乱码,通过查阅资料并学习最终解决了问题。以下是解决方法和学习笔记。

获取数据

用axios发送请求。我用到的是post请求,

{ url: 'your url', method: 'post', /* 一定要加这个 否则就会乱码 */ responseType: 'arraybuffer', } XMLHttpRequest.responseType是一个枚举字符串值,用于指定响应中的数据类型。(还有别的值,可根据实际需要选择) 当值arraybuffer时表示一个包含二进制数据的JavaScript ArrayBuffer。 ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。 ps.就是因为这个responseType,卡了我两三个小时,我在别人写的博客里其实也看到过这个参数,但是没往这个上想,平时发请求也没用过这个参数,这次新的知识又增加了。 将二进制数据变成blob

res是获取到的原始二进制数据

const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。 构造函数Blob(blobParts[, options]) blobParts 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings会被编码为UTF-8。 options是一个可选的BlobPropertyBag字典,它可能会指定如下两个属性: type,默认值为 "",它代表了将会被放入到blob中的数组内容的MIME类型 endings,默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入。 它是以下两个值中的一个: native,代表行结束符会被更改为适合宿主操作系统文件系统的换行符 transparent,代表会保持blob中保存的结束符不变 直接打印blob对象,会得到 consoleblob.png 这只能看到大小和MIME类型,想看文本内容的话酱紫: const READER = new FileReader(); READER.addEventListener('loadend', (e) => { console.log(e.target.result);// 此处输出结果 }); READER.readAsText(blob);

blobtext.png ok啦

MIME类型,媒体类型(通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。 这次只用到了excel,需要用别的的时候去网上查一下就行,下面这个是.csv文件的type { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;" } 下载文件

用filer-saver下载,blob是上一步处理好的Blob对象。我这次要下载的是一个excel文件

import FileSaver from 'file-saver'; FileSaver.saveAs(blob, 'filename.xlsx');

这一步就是纯粹的API调用。

合起来酱紫 const getListAll = () => { setExportLoading(true); getExcel({ params: { ...queryParams, }, }, { responseType: 'arraybuffer' }).then((res) => { if (res) { const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); FileSaver.saveAs(blob, 'filename.xlsx'); } }).finally(() => { setExportLoading(false); }); }; 补充-为什么增加了responseType后,返回结果就能正常处理了。 打印看看结果

先打印出,加和不加responseType: 'arraybuffer'时原始数据和blob缓冲区的数据 控制台打印加了responseType: 'arraybuffer'的结果 res.png 控制台打印不加responseType: 'arraybuffer'的结果 乱码.png 打印加了responseType: 'arraybuffer'的blob缓冲区 add.png 打印不加responseType: 'arraybuffer'的blob缓冲区 noadd.png

用其他的不需要responseType就可以正常返回对象或者数组的接口试一下,给他加上responseType: 'arraybuffer', 分别在network和控制台打印一下结果,发现请求的资源就是很正常的我们期待返回的结果, 但是控制台里,就是个这 arraybuffer.png

这时候推出:加或者不加responseType: 'arraybuffer'获取到的资源都是固定的(在network里看到的东西没有变化),加上这个会限制res(响应结果)的类型(加上responseType: 'arraybuffer'后打印出的res就是个ArrayBuffer对象)。

再查一下打印出来的东西都代表啥意思 ArrayBufferByteLength表示ArrayBuffer的大小,单位是字节。

Int8Array 类型数组表示二进制补码8位有符号整数的数组。 Uint8Array 数组类型表示一个8位无符号整型数组

这一堆数组都是二进制数组,应该就是这些数组里存放了文件相关的信息。

结论

一般情况下,我们发请求都不加这个responseType: 'arraybuffer',不加的时候默认值是text,会指定response是DOMString对象中的文本,所以平时不加responseType也没事。导出文件这个需求这里,后端返回的是二进制文件,这时候要是不加responseType,二进制流会被当成DOMString解析成一段乱码的字符串,这时候用乱码的字符串构建去的blob对象,显然不是预期的结果,所以会造成导出文件乱码或者文件打不开(被破坏)。我们预期的是用返回的二进制数据构建blob,这时候必须指定响应数据的类型,浏览器才能正确的处理数据。 这时候又有新的问题,浏览器是怎么解析响应正文的呢?



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有