解锁 Chrome 扩展程序消息传递的结构化克隆

Justin Lulejian
Justin Lulejian

发布时间:2026 年 4 月 13 日

不同扩展程序组件(后台脚本、内容脚本、弹出式窗口)之间的通信传统上依赖于 JSON 序列化。虽然 JSON 可靠,但也有局限性。

我们很高兴地宣布,从 Chrome 148 开始,扩展程序开发者可以选择使用结构化克隆算法进行消息序列化,而不是使用 JSON!通过这种现代化方式,您可以在扩展程序上下文之间发送更复杂的数据类型,而无需手动进行序列化处理。

为什么要使用结构化克隆?

JSON 序列化(通过 JSON.stringify 在后台进行)是可行的,但有时在处理现代 JavaScript 类型时,开发者需要费一番周折。

下面是一个您在开发扩展程序时可能遇到的具体示例:

// Sending a Map with JSON serialization
const myMap = new Map([['id', 123]]);

// Arrives as {} on the other side!
chrome.runtime.sendMessage(myMap);

// Workaround: Convert Map to an Array of entries before sending
const message = Array.from(myMap.entries());
chrome.runtime.sendMessage(message);

// On the receiving side:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  const receivedMap = new Map(message);
});

您可能不得不解决的其他一些 JSON 失败情况包括 SetBigIntNaNInfinityDate 以及 Error 对象。

使用结构化克隆序列化意味着您现在可以通过扩展消息传递发送之前难以或无法传输的各种对象。例如,发送 Map 对象现在是直接发送:

// Sending a Map with Structured Clone
const myMap = new Map([['id', 123]]);

// Arrives as a Map on the other side!
chrome.runtime.sendMessage(myMap);

// On the receiving side:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  // message is already a Map instance!
  console.log(message.get('id')); // 123
});

更多支持的类型

结构化克隆支持各种其他类型,例如 FileBlob

如何加入计划

为确保向后兼容性并防止现有扩展程序中断,此功能为选择启用。您只需向 manifest.json 添加一个键,即可为扩展程序全局启用该功能:

{
  "name": "My Extension",
  "version": "1.0",
  "manifest_version": 3,
  "message_serialization": "structured_clone"
}

如果省略此属性,或者 Chrome 版本低于 148,浏览器会默认使用当前基于 JSON 的扩展程序实现。

通过支持结构化克隆算法,我们使扩展程序消息传递 API 更接近于标准 Web 平台功能(类似于 Web Worker 和 iframe 通信中使用的 postMessage),从而为您提供更大的灵活性和功能。

互操作性和注意事项

虽然我们的结构化克隆序列化实现支持的类型比 JSON 多得多,但您应注意该实现的一些架构假设和不兼容性。

不支持的类型

我们的实现不支持共享对象(例如 SharedArrayBuffer)和转移对象(例如 ArrayBuffer)。SharedArrayBuffer 将无法序列化或反序列化(具体取决于具体情况),并且尝试发送可转移的对象(例如 Uint8Array)将改为发送副本。

分机到分机的通信

我们强制执行匹配的序列化格式,以确保数据完整性。序列化格式不匹配的扩展程序无法通过 runtime.sendMessageruntime.connect 直接通信。例如,如果扩展程序 A 使用 JSON 序列化,并尝试使用结构化克隆向扩展程序 B 发送消息,则消息将无法发送,并且端口将关闭(反之亦然)。

网页通信

使用 externally_connectable 的网页将自动适应目标扩展程序的序列化格式。如果扩展程序使用结构化克隆,则使用 runtime API 发送消息的网络上下文将自动使用结构化克隆(反之亦然)。这意味着,网站和扩展程序必须在预期序列化格式上保持同步,以防止出现序列化错误。

原生消息传递

原生消息传递渠道始终会强制执行 JSON 序列化。 尝试将仅限结构化克隆的类型(例如 BigInt)发送到原生主机时,会在消息离开扩展程序的上下文之前失败。

toJSON() 方法

如果您使用具有自定义 toJSON() 方法的类或对象来执行自定义序列化(例如,通过移除密码来清理数据,然后再发送对象),请注意,结构化克隆会忽略 toJSON()。它会直接复制属性值。如果您依赖 toJSON() 进行自定义序列化,则可能需要在发送之前进行一些手动操作。例如:

class User {
  constructor(name, password) {
    this.name = name;
    this.password = password;
  }

  // This will be ignored by structured clone!
  toJSON() {
    return { name: this.name };
  }
}

const user = new User("Alice", "secret123");

// JSON -> {"name":"Alice"}
// Structured Clone -> { name: "Alice", password: "secret123" }

JSON 序列化是否会消失?

不需要!在可预见的未来,Chrome 将继续支持这两种序列化格式。

分享反馈

我们希望这项新功能能让您在开发扩展程序时获得更顺畅、更强大的工作流程。

虽然我们已创建测试套件来验证结构化克隆实现的功能,但 Web 平台具有大量不同的对象。请试用这项新功能,并报告您遇到的任何 bug 或极端情况!您的反馈将有助于我们改进整个社区的实施情况。