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

news/2024/4/27 21:03:14/文章来源:https://blog.csdn.net/u011039332/article/details/135612078

前言

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

主要的情况是, 基于 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

 

 

完 

 

 

 

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

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

相关文章

前端Web移动端学习day05

移动 Web 第五天 响应式布局方案 媒体查询Bootstrap框架 响应式网页指的是一套代码适配多端,一套代码适配各种大小的屏幕。 共有两种方案可以实现响应式网页,一种是媒体查询,另一种是使用bootstrap框架。 01-媒体查询 基本写法 max-wid…

如何优化财务管理?中小型外贸企业实用指南

在当今全球化的商业环境中,越来越多的中小企业涉足外贸领域,以寻求更广阔的市场和发展空间。在这一过程中,财务管理的重要性尤为凸显,需关注外汇风险、税务合规性、现金流等多个方面的问题。 一、中小企业外贸财务管理难题 币种核…

Python入门练习 - 学生管理系统

Python 实现读书管理系统 """ 实现一个命令行版的读书管理系统 """ import os.path import sys# 使用这个全局变量,来管理所有的学生信息 # 这个列表的每个元素都是一个‘字典’,每 个 字典就分别表示了一个同学students …

argocd cli工具使用

一、前言 ragocd除了使用web界面操作之外,也可以通过argocd cli工具进行操作,关于集群创建、gitlab仓库创建、app创建都是可以通过yaml 文件去操作,使用web界面创建的操作也需要使用argocd cli工具进行备份 二、使用 在argocd部署的章节已经…

阿里云4核16G服务器优惠价格26元1个月、149元半年

阿里云4核16G服务器优惠价格26.52元1个月、79.56元3个月、149.00元半年。2024年腾讯云服务器优惠价格表,一张表整理阿里云服务器最新报价,阿里云服务器网整理云服务器ECS和轻量应用服务器详细CPU内存、公网带宽和系统盘详细配置报价单,大家也…

MySQL数据库高级语句

文章目录 MySQL高级语句older by 排序区间判断查询或与且(or 与and)嵌套查询(多条件)查询不重复记录distinctcount 计数限制结果条目limit别名as常用通配符嵌套查询(子查询)同表不同表嵌套查询还能用于删除…

Python基础教程:基本数据类型

基本数据类型 不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组) 可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合) Numbers(数字) 数字数据类型用于存储数值。 他们是不可改变的数据类型,这意味着改变数字数据类型会分配一个新的对…

【正点原子FreeRTOS学习笔记】————(12)信号量

这里写目录标题 一、信号量的简介(了解)二、二值信号量(熟悉)三、二值信号量实验(掌握)四、计数型信号量(熟悉)五、计数型信号量实验(掌握)六、优先级翻转简介…

腾讯云GPU云服务器_GPU云计算_异构计算_弹性计算

腾讯云GPU服务器是提供GPU算力的弹性计算服务,腾讯云GPU服务器具有超强的并行计算能力,可用于深度学习训练、科学计算、图形图像处理、视频编解码等场景,腾讯云百科txybk.com整理腾讯云GPU服务器租用价格表、GPU实例优势、GPU解决方案、GPU软…

LinkedIn 互联网架构扩展简史

LinkedIn成立于 2003 年,其目标是连接到您的网络以获得更好的工作机会。第一周只有 2,700 名会员。时间快进了很多年,LinkedIn 的产品组合、会员基础和服务器负载都取得了巨大的增长。 如今,LinkedIn 在全球运营,拥有超过 3.5 亿会…

R使用netmeta程序包实现生存数据的频率学网状meta分析

之前的推文系统的介绍了使用netmeta包实现对二分类变量、连续型变量和罕见事件的网状meta分析。今天的文章介绍如何使用netmeta程序包实现生存数据的频率学网状meta分析,用来评估6种免疫疗法( Camrelizumab、Tislelzumab、Toripalimab、Sintilimab、Pemb…

(二)windows配置JDK环境

1、安装包下载地址,官网:Java Archive | Oracle 长期稳定支持版本8、11、17、21 选择一个需要下载的连接点进去: 在下载列表中根据操作系统选择不同的下载包: 注意:部分版本下载需要先登录后才可以下载。 安装包附件…

Canal解决Redis缓存与Mysql数据库的一致性问题

1、什么是Canal? 如何解决Redis缓存与Mysql数据库的一致性问题?我们常用数据双删缓存超时设置去解决。这样最差的情况,就是在超时时间内,数据存在不一致。 canal,译为管道,主要用途是基于 MySQL 数据库增…

(1) 易经与命运_学习笔记

个人笔记,斟酌阅读 占卦的原理 三个铜板,正面是3,反面2,三个一起转,得出6,7,8,9 数字象6老阴7少阳8少阴9老阳 生数和成数 生数和成数应该说出自《河图》。其中一二三四五为生数,六七八九十为成数。 生…

基于k6和python进行自动化性能测试

摘要:在性能测试中,达到相应的性能指标对于一个软件来说十分重要,在本文中,将介绍一种现代化性能测试工具k6。 import http from k6/http; import { sleep } from k6; export default function () { http.get(https://test-api…

正式发布:VitePress 1.0 现代化静态站点生成器!

大家好,我是奇兵,今天介绍一下现代化静态站点生成器!,希望能帮到大家。 3 月 21 日, 由 Vue 团队出品的现代化静态站点生成器 VitePress 正式发布 1.0 版本!它专为构建快速、以内容为中心的网站而生,能够轻…

动态多态的注意事项

大家好: 衷心希望各位点赞。 您的问题请留在评论区,我会及时回答。 多态的基本概念 多态是C面向对象三大特性之一(多态、继承、封装) 多态分为两类: 静态多态:函数重载和运算符重载属于静态多态&#x…

C语言从入门到实战----C语言中内存函数的使用和模拟实现

目录 前言 1.memcpy 使用和模拟实现 2. memmove 使用和模拟实现 3. memset 函数的使用 4. memcmp 函数的使用 前言 在编程领域,内存管理是至关重要的一环,它确保了程序能够高效、稳定地运行。 C语言作为一门底层的编程语言,提供了一系…

【3D目标检测】Det3d—SE-SSD模型训练(前篇):KITTI数据集训练

SE-SSD模型训练 1 基于Det3d搭建SE-SSD环境2 自定义数据准备2.1 自定义数据集标注2.2 训练数据生成2.3 数据集分割 3 训练KITTI数据集3.1 数据准备3.2 配置修改3.3 模型训练 1 基于Det3d搭建SE-SSD环境 Det3D环境搭建参考:【3D目标检测】环境搭建(OpenP…

Linux非root用户安装mysql5.7

1、下载安装包MySQL :: Download MySQL Community Server 点击Archives 我下载的是5.7.27版本,linux主机直接选择linux-Generic即可,选择第一个包下载即可 2、安装mysql 解压 shell> tar xzvf mysql-5.7.31-linux-glibc2.12-x86_64.tar.gz shell&g…