将响应从远程服务器传输到内容脚本(Chrome 扩展名)
Transfer response from remote server to content script (Chrome extension)
我想达到的目标:
单击我的 Chrome 扩展程序的图标后,会显示一个从远程位置下载的文件,并向用户显示另存为对话框。
注意事项:我使用的是 Google 的最新清单,即 v3
。
我已经编辑了这个 post 很多次,因为我能够取得越来越多的成就。我只留下我最新的代码。
tl;dr 现在几乎所有 works.Crucial 东西都丢失了:来自服务器(正文)的响应未保存。而是保存字符串 [object Object]
。
// when icon is clicked
chrome.action.onClicked.addListener(tab => {
if (tab.url.startsWith('http')) {
post({url: tab.url})
.then(async res => ({
filename: getFilename(res.headers.get('Content-Disposition')),
blob: await res.blob()
}))
.then(response => {
console.log(response);
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: saveFile,
args: [response.filename, response.blob],
})
})
.catch((error) => chrome.scripting.executeScript({
target: {tabId: tab.id},
func: showAlert,
args: [error],
}));
}
});
function getFilename(header) {
return /filename="(.+)"/.exec(header)[1];
}
async function post(data = {}) {
return await fetch('http://localhost:5000/citation',{
method: 'POST',
body: new URLSearchParams(data)
});
}
function showAlert(error) {
let message = error.error !== null ? error.error : error.message;
alert("Error: " + message);
}
async function saveFile(filename, blob) {
let link = document.createElement('a');
let url = window.URL.createObjectURL(new Blob([blob],
{type: 'application/octet-stream'}));
link.href = url;
link.download = filename;
link.click();
// For Firefox it is necessary to delay revoking the ObjectURL.
setTimeout(() => {
window.URL.revokeObjectURL(url);
}, 250);
}
问题在于将 blob
对象从 chrome 扩展序列化到内容脚本,我认为这是 chrome 中的错误。如果您尝试记录 saveFile()
收到的 blob 对象,您会注意到它是一个空对象。
因此,您必须将另一个可序列化对象传递给内容脚本,而不是传递 blob
对象。
我已将 blob
对象转换为 base64
对象,然后将其传递给内容脚本。
首先,让我们创建一个函数,将 blob
对象转换为 base64
对象
function blobToBase64(blob) {
return new Promise((resolve, _) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
}
然后转换blob
对象
chrome.action.onClicked.addListener(tab => {
if (tab.url.startsWith('http')) {
post({url: tab.url})
.then(async res => ({
filename: getFilename(res.headers.get('Content-Disposition')),
blob: await res.blob()
}))
.then(async response => {
var base64 = await blobToBase64(response.blob)
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: saveFile,
args: [response.filename, base64],
})
})
.catch((error) => chrome.scripting.executeScript({
target: {tabId: tab.id},
func: showAlert,
args: [error],
}));
}
});
然后在saveFile()
方法中,你需要将那个base64
转换成一个文件
async function saveFile(filename, base64URL) {
fetch(base64URL)
.then(res => res.blob())
.then(blob => {
let link = document.createElement('a');
let url = window.URL.createObjectURL(new Blob([blob],
{ type: 'application/octet-stream' }));
link.href = url;
link.download = filename;
link.click();
// For Firefox it is necessary to delay revoking the ObjectURL.
setTimeout(() => {
window.URL.revokeObjectURL(url);
}, 250);
})
}
如果您在 saveFile()
中不执行任何操作但下载文件,那么最好从扩展本身下载文件,因为将 blob
转换为 base64
然后再次将其恢复为 blob
会减慢下载过程。
我想达到的目标: 单击我的 Chrome 扩展程序的图标后,会显示一个从远程位置下载的文件,并向用户显示另存为对话框。
注意事项:我使用的是 Google 的最新清单,即 v3
。
我已经编辑了这个 post 很多次,因为我能够取得越来越多的成就。我只留下我最新的代码。
tl;dr 现在几乎所有 works.Crucial 东西都丢失了:来自服务器(正文)的响应未保存。而是保存字符串 [object Object]
。
// when icon is clicked
chrome.action.onClicked.addListener(tab => {
if (tab.url.startsWith('http')) {
post({url: tab.url})
.then(async res => ({
filename: getFilename(res.headers.get('Content-Disposition')),
blob: await res.blob()
}))
.then(response => {
console.log(response);
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: saveFile,
args: [response.filename, response.blob],
})
})
.catch((error) => chrome.scripting.executeScript({
target: {tabId: tab.id},
func: showAlert,
args: [error],
}));
}
});
function getFilename(header) {
return /filename="(.+)"/.exec(header)[1];
}
async function post(data = {}) {
return await fetch('http://localhost:5000/citation',{
method: 'POST',
body: new URLSearchParams(data)
});
}
function showAlert(error) {
let message = error.error !== null ? error.error : error.message;
alert("Error: " + message);
}
async function saveFile(filename, blob) {
let link = document.createElement('a');
let url = window.URL.createObjectURL(new Blob([blob],
{type: 'application/octet-stream'}));
link.href = url;
link.download = filename;
link.click();
// For Firefox it is necessary to delay revoking the ObjectURL.
setTimeout(() => {
window.URL.revokeObjectURL(url);
}, 250);
}
问题在于将 blob
对象从 chrome 扩展序列化到内容脚本,我认为这是 chrome 中的错误。如果您尝试记录 saveFile()
收到的 blob 对象,您会注意到它是一个空对象。
因此,您必须将另一个可序列化对象传递给内容脚本,而不是传递 blob
对象。
我已将 blob
对象转换为 base64
对象,然后将其传递给内容脚本。
首先,让我们创建一个函数,将 blob
对象转换为 base64
对象
function blobToBase64(blob) {
return new Promise((resolve, _) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
}
然后转换blob
对象
chrome.action.onClicked.addListener(tab => {
if (tab.url.startsWith('http')) {
post({url: tab.url})
.then(async res => ({
filename: getFilename(res.headers.get('Content-Disposition')),
blob: await res.blob()
}))
.then(async response => {
var base64 = await blobToBase64(response.blob)
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: saveFile,
args: [response.filename, base64],
})
})
.catch((error) => chrome.scripting.executeScript({
target: {tabId: tab.id},
func: showAlert,
args: [error],
}));
}
});
然后在saveFile()
方法中,你需要将那个base64
转换成一个文件
async function saveFile(filename, base64URL) {
fetch(base64URL)
.then(res => res.blob())
.then(blob => {
let link = document.createElement('a');
let url = window.URL.createObjectURL(new Blob([blob],
{ type: 'application/octet-stream' }));
link.href = url;
link.download = filename;
link.click();
// For Firefox it is necessary to delay revoking the ObjectURL.
setTimeout(() => {
window.URL.revokeObjectURL(url);
}, 250);
})
}
如果您在 saveFile()
中不执行任何操作但下载文件,那么最好从扩展本身下载文件,因为将 blob
转换为 base64
然后再次将其恢复为 blob
会减慢下载过程。