我有一个日志记录机制,可以将日志保存到数组中。我需要一种将日志下载到文件中的方法。
我之前(在清单 v2 上)使用过此功能
const url = URL.createObjectURL(new Blob(reallyLongString, { type: 'text/plain' }));
const filename = 'logs.txt';
chrome.downloads.download({url, filename});
现在我正在迁移到清单 v3,并且由于清单 v3 没有
URL.createObjectURL
,因此您无法创建要传递到 chrome.downloads.download
的 url
相反,可以使用类似的东西创建 Blob URL
const url = `data:text/plain,${reallyLongString}`;
const filename = 'logs.txt';
chrome.downloads.download({url, filename});
问题是
chrome.downloads.download
似乎对url参数中传递的字符数有限制,并且下载的文件只包含字符串的一小部分。
那么有什么方法可以克服这个限制呢?
希望在 https://crbug.com/1224027 中实现直接在 Service Worker 中下载 Blob 的方法。
示例:https://stackoverflow.com/a/77427098
它使用 chrome.offscreen API 启动一个不可见的 DOM 页面,我们可以在其中调用 URL.createObjectURL,将结果传递回 SW,SW 将使用它进行 chrome.downloads.download。
算法如下:
async function downloadBlob(blob, name, destroyBlob = true) {
// When `destroyBlob` parameter is true, the blob is transferred instantly,
// but it's unusable in SW afterwards, which is fine as we made it only to download
const send = async (dst, close) => {
dst.postMessage({blob, name, close}, destroyBlob ? [await blob.arrayBuffer()] : []);
};
// try an existing page/frame
const [client] = await self.clients.matchAll({type: 'window'});
if (client) return send(client);
const WAR = chrome.runtime.getManifest().web_accessible_resources;
const tab = WAR?.some(r => r.resources?.includes('downloader.html'))
&& (await chrome.tabs.query({url: '*://*/*'})).find(t => t.url);
if (tab) {
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: () => {
const iframe = document.createElement('iframe');
iframe.src = chrome.runtime.getURL('downloader.html');
iframe.style.cssText = 'display:none!important';
document.body.appendChild(iframe);
}
});
} else {
chrome.windows.create({url: 'downloader.html', state: 'minimized'});
}
self.addEventListener('message', function onMsg(e) {
if (e.data === 'sendBlob') {
self.removeEventListener('message', onMsg);
send(e.source, !tab);
}
});
}
下载器.html:
<script src=downloader.js></script>
downloader.js、popup.js、options.js 和其他扩展页面脚本(不是内容脚本):
navigator.serviceWorker.ready.then(swr => swr.active.postMessage('sendBlob'));
navigator.serviceWorker.onmessage = async e => {
if (e.data.blob) {
await chrome.downloads.download({
url: URL.createObjectURL(e.data.blob),
filename: e.data.name,
});
}
if (e.data.close) {
window.close();
}
}
manifest.json:
"web_accessible_resources": [{
"matches": ["<all_urls>"],
"resources": ["downloader.html"],
"use_dynamic_url": true
}]
警告! 由于
"use_dynamic_url": true
尚未实现,如果您不想让网页检测到您的扩展,请不要添加 web_accessible_resources。