我正在构建一个chrome扩展,在其中从用户那里获取一个文件作为输入,并将其传递给background.js(manifest v3中的service worker)将其保存到我的后端。由于内容脚本阻止了跨源请求,我必须将其传递到我的background.js
并使用FETCH API保存文件。当我将FormData
或File
对象传递给chrome.runtime.sendMessage
API时,它使用JSON序列化,而我在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
(推荐here)。有人能帮助我解决这个问题吗?我被这种行为所阻碍。
3条答案
按热度按时间mklgxw1f1#
目前只有Firefox可以直接传输这些类型,Chrome可能可以在future中实现。
变通方案1。
手动将对象的内容序列化为字符串,发送该字符串(如果长度超过64 MB消息大小限制,则可能分几条消息发送),然后在后台脚本中重新生成对象。下面是一个简化的示例,没有拆分,改编自Violentmonkey,比较慢(50 MB的编码和解码需要几秒钟),因此您可能希望编写自己的版本,在内容脚本中构建
multipart/form-data
字符串,并在后台脚本中直接发送它。sfetch
。解决方法2。
对通过web_accessible_resources公开的扩展中的html文件使用iframe。
iframe将能够做扩展所能做的一切,比如发出CORS请求。
File/Blob和other cloneable types可以通过postMessage从内容脚本直接传输。FormData不可克隆,但可以将其作为
[...obj]
传递,然后组装到new FormData()
对象中。它还可以通过navigator.serviceWorker消息传递将数据直接传递给后台脚本。
示例:参见that answer中的“Web消息(双向MessagePort)”。
gojuced72#
我有个更好的办法你可以把Blob存储在IndexedDB中。
tyky79it3#
我发现了另一种方法来将文件从内容页面(或从弹出页面)传递给服务工作者。但是,可能,它并不适合所有情况,
你可以在服务工作器中拦截从内容或弹出页面发送的获取请求,然后你可以通过服务工作器发送这个请求,它也可以被修改
popup.js:
background.js: