当前位置: 首页 > 面试题库 >

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

齐高寒
2023-03-14
问题内容

我有一个内容脚本,该脚本使用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
Object]”。我猜发生这种情况是因为ArrayBuffer类型从内容过程转移到后台时以某种方式丢失了吗?我该如何解决?


问题答案:

在内容脚本和背景页面之间传递的消息是JSON序列化的。

如果要ArrayBuffer通过JSON序列化的通道传输对象,请在传输之前和之后将缓冲区包装在视图中。

我展示了一个孤立的示例,以便该解决方案通常适用,而不仅仅是您的情况。该示例显示了如何传递ArrayBuffers和类型数组,但是该方法也可以通过使用API
应用于FileBlob对象FileReader

// In your case: self.data = { data: new Uint8Array(xhr.response), ...
// Generic example:
var example = new ArrayBuffer(10);
var data = {
    // Create a view
    data: Array.apply(null, new Uint8Array(example)),
    contentType: 'x-an-example'
};

// Transport over a JSON-serialized channel. In your case: sendResponse
var transportData = JSON.stringify(data);
//"{"data":[0,0,0,0,0,0,0,0,0,0],"contentType":"x-an-example"}"

// At the receivers end. In your case: chrome.extension.onRequest
var receivedData = JSON.parse(transportData);

// data.data is an Object, NOT an ArrayBuffer or Uint8Array
receivedData.data = new Uint8Array(receivedData.data).buffer;
// Now, receivedData is the expected ArrayBuffer object

此解决方案已在Chrome 18和Firefox中成功测试。

  • new Uint8Array(xhr.response) 用于创建的视图ArrayBuffer,以便可以读取各个字节。
  • Array.apply(null,<Uint8Array>)用于使用Uint8Array视图中的键创建普通数组。此步骤减小了序列化消息的大小。 警告:此方法仅适用于少量数据。 当类型化数组的大小超过125836时,将引发RangeError。如果需要处理大量数据,请使用其他方法在类型数组和纯数组之间进行转换。

  • 在接收者端,可以通过创建一个新Uint8Array缓冲区并读取buffer属性来获得原始缓冲区。

在您的Google Chrome浏览器扩展程序中实施:

// 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;

文献资料

  • MDN:类型化数组
  • MDN: ArrayBuffer
  • MDN: Uint8Array
  • MDN: <Function> .apply
  • Google Chrome扩展程序文档:消息传递>简单的一次性请求
    “这使您可以分别 从内容脚本向扩展程序发送一次 JSON可序列化的消息 ,反之亦然”


 类似资料:
  • 问题内容: 我知道这个问题已经在很多帖子中问过了,但老实说我不明白。我不熟悉JavaScript,Chrome扩展程序和其他所有功能,并且已经完成了此类课程。因此,我需要制作一个插件,该插件将使用跨域请求在任何给定页面上计算DOM对象。到目前为止,我已经可以使用Chrome Extension API来实现这一目标。现在的问题是,我需要在contentScript.js文件的popup.html页

  • 问题内容: 我正在做一个插件来对界面进行一些转换。我不断收到(典型的跨网站问题) 但作为扩展程序,它应该可以访问iframe的内容 … 没有人知道如何访问它的内容以便可以被捕获吗? 问题答案: 通常,没有直接访问其他来源对象的直接方法。如果要在不同框架中的内容脚本之间 安全地 通信,则必须将消息发送到后台页面,该页面又将消息发送回选项卡。 这是一个例子: 的一部分: : : 后台脚本“ bg.js

  • 问题内容: 在Chrome应用中,我正在使用JavaScript XHR(尤其是角度$ http GET,响应类型为“ blob”)从服务器下载blob内容 如何将其保存到chrome应用程序的文件系统中? 当前在HTML5文件系统API上使用Angular包装器 https://github.com/maciel310/angular- filesystem 我不想向用户显示弹出窗口(因此无法使

  • 问题内容: 我正在尝试让我的Chrome扩展程序在加载新页面时运行该功能,但是在尝试了解如何执行此操作时遇到了麻烦。据我了解,我需要在background.html中执行以下操作: 使用来检查时,页面变更 使用运行的脚本。 这是我的代码: 我还想知道init()函数是否可以访问位于其他JS文件中的其他函数? 问题答案: Chrome扩展程序中的JavaScript代码可以分为以下几类: 扩展代码-

  • 我正在研究Blob,我注意到当你有一个ArrayBuffer时,你可以很容易地将它转换成Blob,如下所示: 我现在的问题是,有没有可能从一团变成一团?

  • 问题内容: 我有一个chrome扩展程序,可以在网站上进行一些更改(编辑评论)。 在站点上进行了最近更改之后(站点不是我的站点)-使用ajax加载了注释块(之前是简单的发布请求,整个页面都重新加载了)。 现在,如果我第一次加载页面-内容脚本可以工作,但是当我转到下一页时,说页面#2-使用ajax添加注释,并且不再运行扩展脚本。所以评论并没有改变我想要的方式。 有没有简单的方法来监听页面更改DOM并