42 ajax 下载文件未配置 responseType blob 导致的文件异常

前言

这是一个最近的关于文件下载碰到的一个问题 

主要的情况是, 基于 xhr 发送请求, 获取下载的文件 

然后 之后 xhr 这边拿到 字节序列之后, 封装 blob 来进行下载 

然后 最开始我们这边没有配置 responseType 为 blob, arraybuffer, 然后 导致下载出来的 文件大小超过了一倍,m 并且解压出现了问题 

然后 增加了 responseType 配置为 blob 之后, 文件下载的功能就正常了 

这里来大致看一下 大体的一个情况, 因为 xhr 这边具体的 编码 response, responseText, responseXml 的代码查看不了, 因此看不到 字节序列 转换为 字符串的过程, 因此 这里的结论仅仅是一个 大致的推导

另外 js 这边 new Blob 的具体的代码 也是查看不了, 因此 查看不了 字符串 转换为 字节序列 的这个过程

 

 

测试用例

客户端这边发送请求的 demo 代码如下 

  ajax({
    method: 'post',
    url: '/xxx/file/batchDownload',
    data: data,
    // responseType: 'arraybuffer'
  }).then(res => {
	let blob = new Blob([res], {type: "application/zip"});
	const link = document.createElement("a");
	link.download = 'file.zip';
	link.style.display = "none";
	link.href = URL.createObjectURL(blob);
	document.body.appendChild(link);
	link.click();
	URL.revokeObjectURL(link.href);
	document.body.removeChild(link);
  }).finally(() => {
	this.setdownLoading(row, false)
  })

 

 

正常的情况

如下是一个列表展示, 原始正确的 zip 文件大小为 811667 字节 

// 原始文件大小 
blob 
	811667 
	
// 原始字节序列 使用给定的编码编码为字符序列, 然后再使用相同的编码解码为字节序列 
new String(baos.toByteArray(), $charset).getBytes($charset)
	gbk : 810632 
	utf8 : 1475674 

// 前端 xhr 代码中不配置 responseType 为 arraybuffer/blob 的情况 
xhr, without responseType blob, new Blob([res], {type: "application/zip"});
1476964

 

服务器这边响应的正常的 zip 文件大小如下, 是正确的, 可以正常打开 

f8e920720ead432db262d726bfd4443a.png

 

然后 我们看一下 正常的情况, 即 ajax 增加 responseType 为 blob/arraybuffer 的情况 

这里是 axios 中的基于 xhr 的一个适配器, 这里是具体的基于 XmlHttpRequest 发送请求的地方 

我们可以看到 response 为 blob, 然后 字节数为 811667 拿到的是正常的数据 

011045c7d5a246159862b19cb79be9cc.png

 

然后 进而再外层 业务 handle 处理的时候 也是拿到的正确的数据

然后 最终下载的压缩包, 正常 

631b159d4309404ab346a7a94d77a373.png

 

 

异常的情况

然后 这里可以看到的是 responseData 是一个字符串, 说明 他已经被转换过了 

因为 服务器那边传输的是原始的字节序列, 然后 这里被转换过了之后 可能会造成 字节序列 的数据丢失, 错误 

可以看到 这里数据大小是 1.5M 大概是原始数据的两倍, 字节转字符的编码可能是 gbk 或者 utf8

ec426fe35cc74bd4b0ee15ab0b4bfb8b.png

 

然后 业务这边再根据 字符串传唤为字节序列, 存放到 blob, 拿到的也是一个错误的数据 

可以看到这里数据量大小为 1476944 和上面表格统计的大小基本一致, 之所以说基本一致, 是因为多次下载 会有少许不同, 大小差距在 20字节左右 

c5e215cb58114cb2859ff525b5ba0d55.png

 

所以 综上问题就在于在这个 字节序列 转 字符序列 再转 字节序列 的过程中造成了数据的错误

这个过程 会经过两次字符编码体系的处理

  1. 如果这两次都是 相同的单字节编码, 那么不会出现问题
  2. 如果是两次都是 相同的多字节编码 则可能存在问题, 因为 目标字节序列 可能未必复合目标编码的格式约束, 然后 造成了数据的不可逆丢失
  3. 如果是两次是 不同的编码, 并且存在兼容的 codepoint, 而且 字节序列 中的数据均在这些兼容的 codepoint 范围内, 则不会出现问题, 否则 会出现数据错误

但是 目标字节序列, 是 zip 格式, 任何一个字节的错误 都可能造成整体文件 不符合 zip 的规范, 或者 最开始 验签的时候 就校验不通过

 

 

字节序列 使用 utf8编码转换为字符串, 然后再依据utf8编码转换为字节序列, 数据会不会丢失?

// 原始文件大小 
blob 
	811667 
	
// 原始字节序列 使用给定的编码编码为字符序列, 然后再使用相同的编码解码为字节序列 
new String(baos.toByteArray(), $charset).getBytes($charset)
	gbk : 810632 
	utf8 : 1475674 

 

这里我们先来看下 这里例子中的文件的情况, 这里就解释了 不配置 responseType 为 arraybuffer/blob 的情况下下载出来的数据是错误的问题 

使用 utf8 的时候, 整个过程最终结果的字节序列长度为 1475674

9a21c8df869f4c10a866837678bc8694.png

 

使用 gbk 的时候, 整个过程最终结果的字节序列长度为 810632

ef3a7ab8f1da4e1aa0d2cf642a9157b0.png

 

然后 我们这里来看拿一下 上面的转换之后, 什么情况下 数据会丢失? 什么情况下 数据不丢失? 

如果 字节序列是满足 utf8 的编码规范, 则数据不会丢失, 否则 可能会有数据丢失

比如这里是原始字节序列 不满足 utf8 的编码规范, 然后 造成了数据的丢失, 原始 仅仅有 6 个字节, 转换之后却有 18 个字节, 并且 数据还存在错误

b68040b63ef2412eb288a1d544c27495.png

 

比如这里是原始字节序列 满足 utf8 的编码规范, 然后 可以看到的是 原始字节序列 和 目标字节序列 是相同的

222953164db24c58bf507f42be8baa43.png

 

 

但是我们的目标文件是一个 zip 格式的二进制文件, 我们不能确保它的字节序列满足 固定的字符编码[假设浏览器这边是以 utf8 进行编码解码] 

所以 如果是存在一个这个转换过程的话, 是可能存在 字节序列的数据的错误, 丢失 

进而 导致 下载下来的文件, zip 解压缩软件 识别出错

355f358219e7454197a1f77ab798d7d5.png

 

 

完 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/487986.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于前端技术实现的全面预算编制系统

前言 在现代商业环境中,预测销售数据和实际成本是每个公司CEO和领导都极为重视的关键指标。然而,由于市场的不断变化,准确地预测和管理这些数据变得愈发具有挑战性。为了应对这一挑战,建立一个高效的系统来管理和审查销售数据的重…

QT环境搭建

学习QT 一、QT环境搭建二、QT的SDK下载三、认识QT SDK 中自带的一些程序 一、QT环境搭建 QT开发环境,需要安装三个部分。 c编译器(gcc、cl.exe……不是visual studio)QT SDK(QT SDK里面已经内置了C编译器;SDK就是软件…

如何使用Harmony OS控制外设——输入输出?

相关知识点 Hi3861开发板第一个示例程序演示 熟悉使用DevEco Device Tool插件进行程序烧录 熟悉串口调试工具sscom的使用 官方文档中控制核心板上LED的led_example.c讲解及演示 源码路径:applications/sample/wifi-iot/app/iothardware/led_example.cHarmony OS …

docker--Dockerfile (三)

1,Dcockerfile是什么 docker推荐使用dockerfile的定义文件和docker build命令来构建镜像。dockerfile使用基本的基于DSL(面向领域语言)语法的指令来构建Docker镜像。另一种创建Docker镜像的方式是使用docker commit,不推荐使用。 …

酷开系统让用户和电视双向传递,酷开科技实现商业变现

电视在我们的日常生活中扮演着重要的角色。虽然,作为客厅C位的扛把子——电视的娱乐作用深入人心,但是,它的涵义和影响力却因我们每个人的具体生活环境而存在着种种差异,而我们的生活环境又受到我们所处的社会及文化环境的影响。 …

6.使用个人用户登录域控的成员服务器,如何防止个人用户账号的用户策略生效?

(1)需求: (2)实战配置步骤 第一步:创建新的策略-并编辑策略 第二步:将策略应用到服务器处在OU 第三步:测试 (1)需求: 比如域控,或者加入域的…

以XX大学校园为例的智慧能源管理系统建设方案【能源物联网+智能微电网数字校园、节能校园、低碳校园】

建设背景 贯彻落实《中共中央 国务院关于完整准确全面贯彻新发展理念做好碳达峰碳中和工作的意见》和《国务院关于印发2030年前碳达峰行动方案的通知》要求,把绿色低碳发展纳入国民教育体系。 2021年3月26日为推动信息技术与教育教学深度融合,教育部印…

AI基础知识扫盲

AI基础知识扫盲 AIGCLangchain--LangGraph | 新手入门RAG(Retrieval-Augmented Generation)检索增强生成fastGPT AIGC AIGC是一种新的人工智能技术,它的全称是Artificial Intelligence Generative Content,即人工智能生成内容。 …

线性代数 - 应该学啥 以及哪些可以交给计算机

AI很热,所以小伙伴们不免要温故知新旧时噩梦 - 线代。 (十几年前,还有一个逼着大家梦回课堂的风口,图形学。) 这个真的不是什么美好的回忆,且不说老师的口音,也不说教材的云山雾绕,单…

Python程序设计 分支结构

1.判断三角形类型 编写一个能判断三角形类型的小程序。 输入三个数值,判断其是否能构成三角形的三条边。如果能构成,判断其是否等边三角形、直角三角形还是普通三角形。 xeval(input("边长一")) yeval(input("边长二")) zeval(inp…

SQLite使用的临时文件(二)

返回:SQLite—系列文章目录 上一篇:SQLite数据库文件损坏的可能几种情况 下一篇:未发表 ​ 1. 引言 SQLite的显着特点之一它是一个数据库由一个磁盘文件组成。 这简化了 SQLite 的使用,因为移动或备份 数据库就像复制单个文…

linux用户管理1

linux系统可以多用户同时登录,在各自权限下做各自的事情 useradd添加普通用户,之后使用suusername切换用户 所有用户中,root用户权限最大,对应uid,gid均为0,uid为用户编号,gid为用户所在组编号…

力扣算题【第二期】

文章目录 1.反转链表1.1 算法题目1.2 算法思路1.3 代码实现 2.回文链表2.1 算法题目2.2 算法思路2.3 代码实现 1.反转链表 1.1 算法题目 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 1.2 算法思路 1.设置工作指针p,来遍历链表。 2.采…

基于java+SpringBoot+Vue的就业信息管理系统设计与实现

基于javaSpringBootVue的就业信息管理系统设计与实现 开发语言:Java数据库:MySQL技术:SpringBootMyBatis工具:IDEA/Ecilpse、Navicat、Maven 系统展示 前台展示 后台展示 系统简介 本就业信息管理系统以springboot作为框架,b/s模式以及MySql作为后台运行的数据库…

FPGA高端项目:解码索尼IMX327 MIPI相机转HDMI输出,提供FPGA开发板+2套工程源码+技术支持

目录 1、前言2、相关方案推荐本博主所有FPGA工程项目-->汇总目录我这里已有的 MIPI 编解码方案 3、本 MIPI CSI-RX IP 介绍4、个人 FPGA高端图像处理开发板简介5、详细设计方案设计原理框图IMX327 及其配置MIPI CSI RX图像 ISP 处理图像缓存HDMI输出工程源码架构 6、工程源码…

视频码率与分辨率的参考表

视频码率与分辨率的参考表 通常情况下: 1080*720的分辨率,用5000K左右; 720*576的分辨率,用3500K左右; 640*480的分辨率,用1500K左右。

微服务高级篇(四):多级缓存:Nginx本地缓存 --- Redis缓存 --- 进程缓存

文章目录 一、多级缓存概念二、准备工作【导入案例,并搭建Nginx反向代理】2.1 导入商品案例2.1.1 安装MySQL2.1.2 导入SQL2.1.3 导入Demo工程2.1.4 启动2.1.5 导入商品查询页面 三、JVM进程缓存【第三级缓存】3.1 本地进程缓存与分布式缓存的区别3.2 本地进程缓存&a…

huawei 华为 交换机 配置 LACP 模式的链路聚合示例 (交换机之间直连)

组网需求 如 图 3-22 所示, SwitchA 和 SwitchB 通过以太链路分别都连接 VLAN10 和 VLAN20 的网络,且SwitchA 和 SwitchB 之间有较大的数据流量。用户希望 SwitchA 和 SwitchB 之间能够提供较大的链路带宽来使相同VLAN 间互相通信。在两台 Switch 设备上…

从政府工作报告中的IT热词统计探计算机行业发展(三)智能网联新能源汽车:2次

从政府工作报告探计算机行业发展 政府工作报告作为政府工作的全面总结和未来规划,不仅反映了国家整体的发展态势,也为各行各业提供了发展的指引和参考。随着信息技术的快速发展,计算机行业已经成为推动经济社会发展的重要引擎之一。因此&…

Flask python 开发篇:模型(model)的使用

这里我直接分享方法,因为我还有点没搞太明白,所以暂不叙述过多,后面再来补充 我在对应的版块内(也就是跟蓝图同级别),新增了models.py文件,内容如下: from project import testmyselfdb from sqlalchemy.…