使用 Manifest V3 将 FormData/File 对象从内容脚本传递到 chrome 扩展中的后台脚本

2023-12-10

我正在构建一个 chrome 扩展,其中我从用户那里获取一个文件作为输入,并将其传递给我的 background.js (在清单 v3 的情况下为服务工作线程)以将其保存到我的后端。由于内容脚本阻止了跨域请求,因此我必须将其传递给我的background.js并使用 FETCH API 保存文件。当我通过FormData or File反对chrome.runtime.sendMessage它使用 JSON 序列化 API 以及我在我的background.js是一个空对象。请参阅下面的代码片段。

//content-script.js

attachFile(event) {
 let file = event.target.files[0];

 // file has `File` object uploaded by the user with required contents. 
 chrome.runtime.sendMessage({ message: 'saveAttachment', attachment: file }); 
}

//background.js

chrome.runtime.onMessage.addListener((request, sender) => {
 if (request.message === 'saveAttachment') {
   let file = request.attachment; //here the value will be a plain object  {}
 }
});

即使我们通过了,也会发生同样的情况FormData从内容脚本。

我参考了旧的 StackOverflow 问题建议的多个解决方案,以使用URL.createObjectURL(myfile);并将 URL 传递给我的background.js并获取相同的文件。而 FETCH API 不支持 blob URL 来获取,而且XMLHttpRequest建议的 Service Worker 不支持here。有人可以帮我解决这个问题吗?我对这种行为感到很受阻。


目前只有 Firefox 可以直接传输此类类型。 Chrome 或许可以在future.

解决方法1。

手动将对象的内容序列化为字符串,如果长度超过 64MB 消息大小限制,可能会在多条消息中发送它,然后在后台脚本中重建该对象。下面是一个没有拆分的简化示例,改编自暴力猴子。它相当慢(50MB 的编码和解码需要几秒钟),因此您可能需要编写自己的版本来构建multipart/form-data内容脚本中的字符串并直接在后台脚本中发送fetch.

  • 内容脚本:

    async function serialize(src) {
      const wasBlob = src instanceof Blob;
      const blob = wasBlob ? src : await new Response(src).blob();
      const reader = new FileReader();
      return new Promise(resolve => {
        reader.onload = () => resolve([
          reader.result,
          blob.type,
          wasBlob,
        ]);
        reader.readAsDataURL(blob);
      });
    }
    
  • 后台脚本,在 onMessage 监听器内:

    const [body, type] = deserialize(message.body);
    fetch(message.url, {
      body,
      headers: {
        'Content-Type': type, 
      },
    }).then(/*........*/);
    function deserialize([base64, type, wasBlob]) {
      const str = atob(base64.slice(base64.indexOf(',') + 1));
      const len = str.length;
      const arr = new Uint8Array(len);
      for (let i = 0; i < len; i += 1) arr[i] = str.charCodeAt(i);
      if (!wasBlob) {
        type = base64.match(/^data:(.+?);base64/)[1].replace(/(boundary=)[^;]+/,
          (_, p1) => p1 + String.fromCharCode(...arr.slice(2, arr.indexOf(13))));
      }
      return [arr, type];
    }
    

解决方法2。

在通过 web_accessible_resources 公开的扩展中使用 iframe 作为 html 文件。
iframe 将能够执行扩展程序可以执行的所有操作,例如发出 CORS 请求。

文件/Blob 和其他可克隆类型可以通过以下方式直接从内容脚本传输发布消息。 FormData 不可克隆,但您可以将其传递为[...obj]然后组装在new FormData() object.

它还可以通过 navigator.serviceWorker 消息传递将数据直接传递到后台脚本。

示例:参见“Web 消息传递(双向 MessagePort)" in 那个答案.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Manifest V3 将 FormData/File 对象从内容脚本传递到 chrome 扩展中的后台脚本 的相关文章

随机推荐