将响应从远程服务器传输到内容脚本(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 会减慢下载过程。