gpt4 book ai didi

javascript - 从 xhr.responseText 恢复 ArrayBuffer

转载 作者:行者123 更新时间:2023-12-01 17:35:52 25 4
gpt4 key购买 nike

我需要从向我发送 base64 答案的 http 请求中获取数组缓冲区。对于这个请求,我不能使用 XMLHttpRequest.responseType="arraybuffer"

我从这个请求中得到的响应是通过 xhr.responseText 读取的。因此它被编码为 DOMString。我正在尝试将其作为数组缓冲区取回。

我尝试使用 btoa(mysString)window.btoa(unescape(encodeURIComponent(str))) 从 DOMString 返回 base64,但是第一个选项只是失败,而第二个选项不提供相同的 base64。每个 base64 的前几个字符示例:

传入:UEsDBBQACAgIACp750oAAAAAAAAAAAAAAALAAAAAX3JlbHMvLnJlbH

第二次处理后:UEsDBBQACAgIAO+/ve+/ve+/vUoAAAAAAAAAAAAAAALAAAAAX3JlbHMvLnJlbH

如您所见,其中一部分相似,但有些部分相差甚远。我缺少什么才能正确处理?

最佳答案

我也遇到了同样的问题。

解决方案(我在 Chrome(68.0.3440.84) 上运行)

let url = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='

let iso_8859_15_table = { 338: 188, 339: 189, 352: 166, 353: 168, 376: 190, 381: 180, 382: 184, 8364: 164 }

function iso_8859_15_to_uint8array(iso_8859_15_str) {
let buf = new ArrayBuffer(iso_8859_15_str.length);
let bufView = new Uint8Array(buf);
for (let i = 0, strLen = iso_8859_15_str.length; i < strLen; i++) {
let octet = iso_8859_15_str.charCodeAt(i);
if (iso_8859_15_table.hasOwnProperty(octet))
octet = iso_8859_15_table[octet]
bufView[i] = octet;
if(octet < 0 || 255 < octet)
console.error(`invalid data error`)
}
return bufView
}

req = new XMLHttpRequest();
req.overrideMimeType('text/plain; charset=ISO-8859-15');
req.onload = () => {
console.log(`Uint8Array : `)
var uint8array = iso_8859_15_to_uint8array(req.responseText)
console.log(uint8array)
}
req.open("get", url);
req.send();


下面是我学到的解决它的解释。

说明

为什么有些部分跑偏了?

because TextDecoder cause data loss (Your case is utf-8).

例如,我们来谈谈UTF-8

  • Unicode 的可变宽度字符编码。

  • 由于可变长度特性和ASCII兼容性等原因,它具有规则(这将成为问题。)

  • 因此,解码器可能会将不符合要求的字符替换为替换字符,例如 U+003F(?, 问号) 或 U+FFFD(�, Unicode 替换字符)。

  • 在utf-8的情况下,0~127的值是稳定的,128~255的值是不稳定的。 128~255会转换成U+FFFD

除 UTF-8 之外的其他文本解码器是否安全?

没有。在大多数情况下,规则并不安全。

UTF-8 也是不可恢复的。 (128~255设置为U+FFFD)

If the binary data and the decoded result can be corresponded to one-to-one, they can be recovered.

如何解决?

  1. 找到可恢复的文本解码器。
  2. 强制 MIME 类型为传入数据的可恢复字符集。xhr_object.overrideMimeType('text/plain; charset=ISO-8859-15')
  3. 在收到时使用recover table 从字符串中恢复二进制数据。

查找可恢复的文本解码器。

为了恢复,避免解码结果重复的情况。

以下代码是一个简单的示例,因此可能缺少可恢复的文本解码器,因为它只考虑了 Uint8Array。

let bufferView = new Uint8Array(256);
for (let i = 0; i < 256; i++)
bufferView[i] = i;

let recoverable = []
let decoding = ['utf-8', 'ibm866', 'iso-8859-2', 'iso-8859-3', 'iso-8859-4', 'iso-8859-5', 'iso-8859-6', 'iso-8859-7', 'iso-8859-8', 'iso-8859-8i', 'iso-8859-10', 'iso-8859-13', 'iso-8859-14', 'iso-8859-15', 'iso-8859-16', 'koi8-r', 'koi8-u', 'macintosh', 'windows-874', 'windows-1250', 'windows-1251', 'windows-1252', 'windows-1253', 'windows-1254', 'windows-1255', 'windows-1256', 'windows-1257', 'windows-1258', 'x-mac-cyrillic', 'gbk', 'gb18030', 'hz-gb-2312', 'big5', 'euc-jp', 'iso-2022-jp', 'shift-jis', 'euc-kr', 'iso-2022-kr', 'utf-16be', 'utf-16le', 'x-user-defined', 'ISO-2022-CN', 'ISO-2022-CN-ext']
for (let dec of decoding) {
try {
let decodedText = new TextDecoder(dec).decode(bufferView);
let loss = 0
let recoverTable = {}
let unrecoverable = 0
for (let i = 0; i < decodedText.length; i++) {
let charCode = decodedText.charCodeAt(i)
if (charCode != i)
loss++

if (!recoverTable[charCode])
recoverTable[charCode] = i
else
unrecoverable++
}
let tableCnt = 0
for (let props in recoverTable) {
tableCnt++
}
if (tableCnt == 256 && unrecoverable == 0){
recoverable.push(dec)
setTimeout(()=>{
console.log(`[${dec}] : err(${loss}/${decodedText.length}, ${Math.round(loss / decodedText.length * 100)}%) alive(${tableCnt}) unrecoverable(${unrecoverable})`)
},10)
}
else {
console.log(`!! [${dec}] : err(${loss}/${decodedText.length}, ${Math.round(loss / decodedText.length * 100)}%) alive(${tableCnt}) unrecoverable(${unrecoverable})`)
}
} catch (e) {
console.log(`!! [${dec}] : not supported.`)
}
}

setTimeout(()=>{
console.log(`recoverable Charset : ${recoverable}`)
}, 10)


在我的控制台中,这个返回

recoverable Charset : ibm866,iso-8859-2,iso-8859-4,iso-8859-5,iso-8859-10,iso-8859-13,iso-8859-14,iso-8859-15,iso-8859-16,koi8-r,koi8-u,macintosh,windows-1250,windows-1251,windows-1252,windows-1254,windows-1256,windows-1258,x-mac-cyrillic,x-user-defined

我在这个答案的开头使用了 iso-8859-15。 (它有最小的表大小。)


附加测试)UTF-8 和 ISO-8859-15 结果的比较

检查U+FFFD在使用ISO-8859-15时是否真的消失了。

function requestAjax(url, charset) {
let req = new XMLHttpRequest();
if (charset)
req.overrideMimeType(`text/plain; charset=${charset}`);
else
charset = 'utf-8';
req.open('get', url);
req.onload = () => {
console.log(`==========\n${charset}`)
console.log(`${req.responseText.split('', 50)}\n==========`);
console.log('\n')
}
req.send();
}

var url = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
requestAjax(url, 'ISO-8859-15');
requestAjax(url);

底线

  • 从字符串中恢复二进制数据需要一些额外的工作。
    • 找到可恢复的文本编码器/解码器。
    • 制作恢复表
    • 用 table 恢复。
    • (你可以引用最上面的代码。)
  • 要使用此技巧,请将传入数据的 MIME 类型强制为所需的字符集。

关于javascript - 从 xhr.responseText 恢复 ArrayBuffer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44974003/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com