我正在构建一个 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(使用前将#替换为@)