突然设置 XMLHttpRequest.responseType 被禁止?

Posted

技术标签:

【中文标题】突然设置 XMLHttpRequest.responseType 被禁止?【英文标题】:Setting XMLHttpRequest.responseType forbidden all of a sudden? 【发布时间】:2012-04-08 22:52:36 【问题描述】:

我一直在使用同步 XMLHttpRequest 并将 responseType 设置为“arraybuffer”来加载二进制文件并等待它加载。今天,我收到了这个错误: “Die Verwendung des responseType-Attributes von XMLHttpRequest wird im synchronen Modus im window-Kontekt nicht mehr unterstützt。” 大致翻译为 “不再支持在 window-context(?) 中以同步模式对 XMLHttpRequest 使用 responseType。”

有谁知道如何解决这个问题?我真的不想对这样的事情使用异步请求。

var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.responseType = 'arraybuffer';

在 chrome 中运行良好。

【问题讨论】:

您可以在 Web Workers 中进行二进制同步 XHR... 【参考方案1】:

这是正确的行为,如Specification of XMLHttpRequest 中所定义:

设置时:如果设置了synchronous flag 并且存在关联的XMLHttpRequest document,则引发"InvalidAccessError" 异常。

XMLHttpRequest 不是异步即同步时,不能设置responseType 属性。将open的第三个参数设置为false会导致请求同步

【讨论】:

对我来说听起来很奇怪,这样的事情应该引发异常。但是感谢您向我指出规范。 @Markus 重点是您不应该编写使用同步 XHR 的新代码。完全删除它会破坏现有网站,但浏览器和规范正试图限制它在新代码中的使用,以便新代码实际上做正确的事情并使用异步 XHR。【参考方案2】:

解决方法

对于普通读者,如果你还需要同步行为,你可以将你的内容下载为字符串,然后将其转换为字节数据

注意:此解决方法假定原始 request.responseASCII 文本。 如果此假设不适合您的特定用例,请参阅jBinary。

我将其转换为ArrayBuffer

var request = new XMLHttpRequest();
request.open('GET', url, false);
request.send(null);

var data;
if (request.status === 200) 
    data = stringToArrayBuffer(request.response);
 else 
    alert('Something bad happen!\n(' + request.status + ') ' + request.statusText);


// ...

function stringToArrayBuffer(str) 
    var buf = new ArrayBuffer(str.length);
    var bufView = new Uint8Array(buf);

    for (var i=0, strLen=str.length; i<strLen; i++) 
        bufView[i] = str.charCodeAt(i);
    

    return buf;

更多阅读

jBinary:用于在 javascript 中处理二进制数据的高级 API。 Sending and Receiving Binary Data:使用原生 Javascript 处理二进制数据。 (来源: Mozilla 开发者网络)

参考文献

Converting between strings and ArrayBuffers Renato Mangini 原函数str2ab Easier ArrayBuffer <-> String conversion with the Encoding API(杰夫·波斯尼克)

【讨论】:

有没有办法准确检索原始二进制(非ascii)二进制数据? @TamasHegedus 为了回答您的问题,我已将我的帖子更新为更多阅读部分。 我怀疑二进制文本二进制转换没有产生原始字节 @TamasHegedus 此处介绍的解决方法在假设原始字节以 ASCII 编码的情况下有效。【参考方案3】:

如果您有幸能够控制整个页面的入口点,请考虑使用 async 函数包装整个内容并使用 await 阻止有问题的异步代码。但可能不适用于所有用例。

(async function () 
    await problem_function_1();
    await problem_function_2();
    ... normal page logic pasted here ...
)(); 

Promise 包装不是promise 的异步代码(以便等待按预期工作),并在任何构成“成功回调”的情况下手动调用resolve 函数。如果可能,对拒绝执行相同的操作。

【讨论】:

【参考方案4】:

由于无法将responseType = 'arraybuffer' 设置为同步模式,因此接收字符串并转换为字节是一种解决方案,但正如 Stephan 所说,您的数据应该是 ascii 文本。您将收到错误的值 (253),而不是 127 以上的所有字节。

但将mime-type 和字符集设置为x-user-defined 可能是一个解决方案:

这里服务器从 125 到 134 发送 10 个字节:

request = new XMLHttpRequest();
request.overrideMimeType('text/plain; charset=x-user-defined');
request.open('GET', url, false);
request.send();
Uint8Array.from(request.response, c => c.charCodeAt(0));
> Uint8Array(10) [125, 126, 127, 128, 129, 130, 131, 132, 133, 134]

不设置 mime-type 是这样的:

request = new XMLHttpRequest();
request.open('GET', url, false);
request.send();
Uint8Array.from(request.response, c => c.charCodeAt(0));
> Uint8Array(10) [125, 126, 127, 253, 253, 253, 253, 253, 253, 253]

【讨论】:

以上是关于突然设置 XMLHttpRequest.responseType 被禁止?的主要内容,如果未能解决你的问题,请参考以下文章

设置这些之后,Google突然可以打开了

PPT突然字间距变大是啥原因

尽管有信任中心设置和数字签名,但 Outlook 2010 中的 VBA 宏突然被禁用?

为啥 spring-vaadin 忘记了我设置的 locale,但在页面刷新后突然记住了?

突然从实体框架中获取异常

怎么安装了cuda,屏幕突然不能设置双屏显示