突然设置 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.response
是 ASCII
文本。
如果此假设不适合您的特定用例,请参阅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 被禁止?的主要内容,如果未能解决你的问题,请参考以下文章
尽管有信任中心设置和数字签名,但 Outlook 2010 中的 VBA 宏突然被禁用?