Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Chrome扩展:如何将ArrayBuffer或Blob从内容脚本传递到后台而不丢失其类型?_Javascript_Json_Google Chrome Extension_Typed Arrays_Xmlhttprequest Level2 - Fatal编程技术网

Javascript Chrome扩展:如何将ArrayBuffer或Blob从内容脚本传递到后台而不丢失其类型?

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,

我有一个内容脚本,它使用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,
        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,)
    用于使用
    Uint8Array
    视图中的键创建普通数组。此步骤将减小序列化消息的大小警告:此方法仅适用于少量数据。当类型化数组的大小超过125836时,将抛出RangeError。如果需要处理大量数据,请使用其他方法在类型化数组和普通数组之间进行转换。

  • 在接收器端,可以通过和读取数据来获得原始缓冲区

在Google Chrome扩展中的实现: 文档
  • MDN:
  • MDN:
  • MDN:
  • MDN:
  • 谷歌浏览器扩展文档:
    “这使您可以从内容脚本向扩展发送一次性的JSON可序列化消息,反之亦然。”
  • 因此,奖励:-使用网络工作者来请求、验证、处理和提交二进制数据

有一种更好的方法可以在同一Chrome扩展的任何部分(内容脚本、背景页面和普通页面)之间传递
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));