You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Manifest V3版Chrome扩展将远程响应传递给content script实现文件另存为问题

问题根源

chrome.scripting.executeScript的参数传递需要经过跨进程序列化,Blob类型无法被正常序列化传递,注入到页面后拿到的实际是普通对象,调用toString()后就变成了[object Object],导致保存的内容错误。

最优解决方案

直接使用Manifest V3原生支持的chrome.downloads API完成下载,不需要注入脚本到页面执行,步骤更简单,也不存在跨进程传值问题:

  1. 先在manifest.json中声明必要权限:
{
  "manifest_version": 3,
  "permissions": ["activeTab", "scripting", "downloads"],
  "host_permissions": ["http://localhost:5000/*"],
  // 其余扩展配置保持不变
}
  1. 修改后台service worker代码如下:
// 点击扩展图标时触发
chrome.action.onClicked.addListener(async tab => {
  if (!tab.url.startsWith('http')) return
  try {
    const res = await post({url: tab.url})
    const filename = getFilename(res.headers.get('Content-Disposition'))
    const blob = await res.blob()
    const blobUrl = URL.createObjectURL(blob)
    // 直接调用下载API,saveAs参数会唤起系统保存对话框
    await chrome.downloads.download({
      url: blobUrl,
      filename: filename,
      saveAs: true
    })
    URL.revokeObjectURL(blobUrl)
  } catch (error) {
    await 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);
}

替代方案(需保留原注入脚本逻辑时使用)

如果必须通过注入页面脚本的方式下载,可以先把Blob转成Base64字符串再传递,字符串可正常跨进程序列化:

  1. 后台传递Base64字符串:
// 拿到blob后转base64
const buffer = await blob.arrayBuffer()
const base64 = btoa(String.fromCharCode(...new Uint8Array(buffer)))
// 注入脚本时传递base64而非blob
chrome.scripting.executeScript({
  target: {tabId: tab.id},
  func: saveFile,
  args: [response.filename, base64],
})
  1. 页面侧saveFile把Base64转回Blob:
async function saveFile(filename, base64) {
  const binary = atob(base64)
  const array = []
  for(let i = 0; i < binary.length; i++) {
    array.push(binary.charCodeAt(i))
  }
  const blob = new Blob([new Uint8Array(array)], {type: 'application/octet-stream'})
  let link = document.createElement('a');
  let url = window.URL.createObjectURL(blob);
  link.href = url;
  link.download = filename;
  link.click();
  setTimeout(() => {
    window.URL.revokeObjectURL(url);
  }, 250);
}

内容的提问来源于stack exchange,提问作者menteith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 13:24:03