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

Justin Lulejian
Justin Lulejian

Published: April 22, 2026

不同扩展程序组件(后台脚本、内容脚本、弹出式窗口)之间的通信传统上依赖于 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"
}

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

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

互操作性和注意事项

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

不支持的类型

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

扩展程序到扩展程序的通信

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

网页通信

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

原生消息传递

原生消息传递通道始终强制使用 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 或极端情况!您的反馈将帮助我们为整个社区改进实现。