Javascript axios如何将blob与arraybuffer作为responseType处理?

Javascript axios如何将blob与arraybuffer作为responseType处理?,javascript,node.js,axios,blob,arraybuffer,Javascript,Node.js,Axios,Blob,Arraybuffer,我正在用下载一个zip文件。为了进一步处理,我需要获取已下载的“原始”数据。就我所见,在Javascript中有两种类型:Blob和Arraybuffers。在请求选项中,两者都可以指定为responseType 在下一步中,需要解压缩zip文件。为此,我尝试了两个库:js-zip和adm-zip。两者都希望数据是ArrayBuffer。到目前为止还不错,我可以将blob转换为缓冲区。在这个转换之后,adm-zip总是愉快地提取zip文件。但是,js zip抱怨文件损坏,除非zip是作为axio

我正在用下载一个zip文件。为了进一步处理,我需要获取已下载的“原始”数据。就我所见,在Javascript中有两种类型:Blob和Arraybuffers。在请求选项中,两者都可以指定为
responseType

在下一步中,需要解压缩zip文件。为此,我尝试了两个库:js-zip和adm-zip。两者都希望数据是ArrayBuffer。到目前为止还不错,我可以将blob转换为缓冲区。在这个转换之后,adm-zip总是愉快地提取zip文件。但是,js zip抱怨文件损坏,除非zip是作为axios
响应类型下载的
'arraybuffer'
。js zip不适用于从
blob
中提取的
缓冲区

这让我很困惑。我认为
ArrayBuffer
Blob
本质上都只是底层内存的视图。作为blob和缓冲区下载某些内容可能在性能上有所不同。但是结果应该是一样的,对吗

好吧,我决定进行实验,发现:

如果指定
responseType:'blob'
,axios会将
响应.data
转换为字符串。假设您对这个字符串进行哈希运算,得到哈希代码A,然后将其转换为缓冲区。对于此转换,您需要指定编码。根据编码的不同,您将得到各种新的散列,我们称它们为B1、B2、B3。。。当指定“utf8”作为编码时,我返回到原始散列A

因此,我猜当以
'blob'
的形式下载数据时,axios会隐式地将其转换为使用utf8编码的字符串。这似乎很合理

现在指定
responseType:'arraybuffer'
。Axios为您提供了一个缓冲区,即
response.data
。对缓冲区进行哈希运算,得到哈希代码C。此代码与a、B1、B2

那么,当以
'arraybuffer'
下载数据时,您会得到完全不同的数据吗

现在对我来说,解压库js-zip抱怨数据是以
'blob'
下载的,这是有道理的。它可能真的被破坏了。但是adm zip如何提取它呢?我检查了提取的数据,它是正确的。这可能只适用于这个特定的zip存档,但仍然让我感到惊讶

以下是我在实验中使用的示例代码:

//typescript import syntax, this is executed in nodejs
import axios from 'axios';
import * as crypto from 'crypto';

axios.get(
    "http://localhost:5000/folder.zip", //hosted with serve
    { responseType: 'blob' }) // replace this with 'arraybuffer' and response.data will be a buffer
    .then((response) => {
        console.log(typeof (response.data));

        // first hash the response itself
        console.log(crypto.createHash('md5').update(response.data).digest('hex'));

        // then convert to a buffer and hash again
        // replace 'binary' with any valid encoding name
        let buffer = Buffer.from(response.data, 'binary');
        console.log(crypto.createHash('md5').update(buffer).digest('hex'));
        //...
是什么造成了这里的差异?我如何获得“真实”下载数据?

来自:

/`responseType`表示服务器将响应的数据类型
//选项有:“arraybuffer”、“document”、“json”、“text”、“stream”
//仅限浏览器:“blob”
responseType:'json',//默认值
“blob”
是“仅浏览器”选项。 因此,在node.js中,当您设置
响应类型:“blob”
,将实际使用
“json”
,我猜在没有获取可解析的json数据时,会回退到
“text”

以文本形式获取二进制数据容易生成损坏的数据。 由于和许多其他API返回的文本是(它们不允许未配对的代理代码点),并且响应被解码为UTF-8,因此二进制文件中的某些字节无法正确映射到字符,因此将被替换为� (U+FFDD)替换字符,无法恢复以前的数据:您的数据已损坏

下面是一个片段,以.png文件
0x89 0x50 0x4E 0x47
的头为例解释了这一点

(异步()=>{
常量url=https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png';
//作为二进制文件获取
const buffer=wait fetch(url).then(resp=>resp.arrayBuffer());
const header=新的Uint8Array(buffer).slice(0,4);
log('binary header',header);//[137,80,78,61]
log('entity encoded',entityEncode(header));
//[“U+0089”、“U+0050”、“U+004E”、“U+0047”]
//你可以在这里阅读更多关于(U+0089)字符的信息
// https://www.fileformat.info/info/unicode/char/0089/index.htm
//您可以在左表中看到UTF-8中的此字符如何需要两个字节(0xC2 0x89)
//因此,我们无法从UTF-16码点在UTF-8中正确映射该字符,
//它将被解析器丢弃并转换为替换字符
//读作UTF-8
const utf8_str=wait new Blob([header]).text();
console.log('读取为UTF-8',utf8_str);/“�巴布亚新几内亚“
//从该字符串构建一个二进制数组
const utf8_binary=[…utf8_str].map(char=>char.charCodeAt(0));
log('whichisbinary',utf8_binary);/[65533,80,78,61]
log('entity encoded',entityEncode(utf8_二进制));
//[“U+FFDD”、“U+0050”、“U+004E”、“U+0047”]
//您可以阅读更多有关角色的信息� (U+FFDD)这里
// https://www.fileformat.info/info/unicode/char/0fffd/index.htm
//
//P(U+0050)、N(U+004E)和G(U+0047)字符在UTF-8和UTF-16之间兼容
//对于这些,没有编码丢失
//(这就是base64编码使以文本形式发送二进制数据成为可能的方式)
//现在,让我们看看作为文本抓取的功能
const fetched_as_text=wait fetch(url)。然后(resp=>resp.text());
const header_as_text=获取的_as_text.slice(0,4);
console.log('fetched as“text',header_as_text);/“�巴布亚新几内亚“
const as_text_binary=[…header_as_text].map(char=>char.charCodeAt(0));
log('whichisbinary',作为_text_binary);/[65533,80,78,61]
log('entity encoded',entityEncode(作为文本和二进制文件));
//[“U+FFDD”、“U+0050”、“U+004E”、“U+0047”]
//它被读取为UTF-8,我们丢失了第一个字节。
})();
功能实体编码(arr){
返回数组.from(arr).map(val=>'U+'+toHex(val));
}
函数toHex(num)