Javascript Chrome扩展:如何将ArrayBuffer或Blob从内容脚本传递到后台而不丢失其类型?
我有一个内容脚本,它使用XHR下载一些二进制数据,稍后发送到后台脚本:Javascript Chrome扩展:如何将ArrayBuffer或Blob从内容脚本传递到后台而不丢失其类型?,javascript,json,google-chrome-extension,typed-arrays,xmlhttprequest-level2,Javascript,Json,Google Chrome Extension,Typed Arrays,Xmlhttprequest Level2,我有一个内容脚本,它使用XHR下载一些二进制数据,稍后发送到后台脚本: var self = this; var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.responseType = 'arraybuffer'; xhr.onload = function(e) { if (this.status == 200) { self.data = { data: xhr.response,
var self = this;
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status == 200) {
self.data = {
data: xhr.response,
contentType: xhr.getResponseHeader('Content-Type')
};
}
};
xhr.send();
... later ...
sendResponse({data: self.data});
在后台脚本中接收到此数据后,我希望形成另一个XHR请求,将此二进制数据上载到我的服务器,因此我执行以下操作:
var formData = new FormData();
var bb = new WebKitBlobBuilder();
bb.append(data.data);
formData.append("data", bb.getBlob(data.contentType));
var req = new XMLHttpRequest();
req.open("POST", serverUrl);
req.send(formData);
问题是上传到服务器的文件只包含以下字符串:“[object]”。我猜这是因为ArrayBuffer类型在从内容进程传输到后台时不知何故丢失了?如何解决这个问题?内容脚本和后台页面之间传递的消息是JSON序列化的 如果要通过JSON序列化通道传输
ArrayBuffer
对象,请在传输前后将缓冲区包装在视图中
我展示了一个单独的示例,这样解决方案就可以普遍适用,而不仅仅是在您的情况下。该示例显示了如何传递ArrayBuffer
s和类型化数组,但该方法也可以通过使用API应用于File
和Blob
对象
该解决方案已在Chrome18和Firefox中成功测试
- 用于创建的视图,以便可以读取单个字节
用于使用Array.apply(null,)
视图中的键创建普通数组。此步骤将减小序列化消息的大小警告:此方法仅适用于少量数据。当类型化数组的大小超过125836时,将抛出RangeError。如果需要处理大量数据,请使用其他方法在类型化数组和普通数组之间进行转换。Uint8Array
- 在接收器端,可以通过和读取数据来获得原始缓冲区
- MDN:
- MDN:
- MDN:
- MDN:
- 谷歌浏览器扩展文档:
“这使您可以从内容脚本向扩展发送一次性的JSON可序列化消息,反之亦然。” - 因此,奖励:-使用网络工作者来请求、验证、处理和提交二进制数据
Blob
(或ArrayBuffer
)然后创建一个普通的JS数组或二进制字符串,并在消息体中传递这个(有时非常大)数据块!记住,它们在发送方端被JSONified,然后在接收方端被取消JSONified
只需创建并传递:
或者首先从ArrayBuffer创建Blob:
var blob = new Blob([ arrayBuffer ], { type: 'image/jpeg' });
sendResponse(URL.createObjectURL(blob));
顺便说一句,XMLHttpRequest 2可以同时返回Blob
和ArrayBuffer
笔记
- 对象URL可以在相当长的时间内处于活动状态,因此如果您不再需要数据,请不要忘记释放此类URL调用
- 对象URL因为任何URL都受到跨源限制的约束,但是扩展的所有部分当然都在同一个源中
- 顺便说一句:当我开始传递这样的URL而不是在我的Chrome扩展中传递数据时,我的性能提高了4倍!(我的数据是相当大的图像。)
Array.apply(null,新的Uint8Array(xhr.response))
不适用于大缓冲区(大于150Kb),导致超过最大调用堆栈大小错误。即使对于较小的缓冲区,也最好传递JS数组的二进制字符串。对于较大的数组Array.from(new-Uint8Array(xhr.response))
对我有效。+1回答不错。除了您所说的:卸载文档时,blob:
URL将自动撤销。如何从objectUrl重新创建blob?@IanT8使用fetch API或XHR从objectUrl下载blob。由于webAccessibleResources或某些网站上的CSP,该blob不起作用。
// Part of the Content script
self.data = {
data: Array.apply(null, new Uint8Array(xhr.response)),
contentType: xhr.getResponseHeader('Content-Type')
};
...
sendResponse({data: self.data});
// Part of the background page
chrome.runtime.onMessage.addListener(function(data, sender, callback) {
...
data.data = new Uint8Array(data.data).buffer;
sendResponse(URL.createObjectURL(blob));
var blob = new Blob([ arrayBuffer ], { type: 'image/jpeg' });
sendResponse(URL.createObjectURL(blob));