Chrome 扩展消息传递体系结构

Chrome Extension Messaging Architecture

本文关键字:体系结构 消息传递 扩展 Chrome      更新时间:2023-12-04

我最近开始开发我的第一个Chrome扩展程序,主要只是为了看看我是否可以做到,我想知道消息究竟是如何传递的机制。这可能是关于windows.postMessage API的一个更普遍的问题,但我想知道是否有人可以解释控制消息接收和传播的幕后过程。

这是我目前对 w.r.t Chrome 扩展程序的消息传递的理解:

  • Javascript有四类:(1)与弹出窗口绑定的JS,(2)在后台运行或作为事件运行的JS,内容脚本中的(3) JS,以及注入页面(4) JS。
  • (2) -> (1)(3) -> (1)runtime.sendMessage()发送。仅当弹出窗口打开时,才会收到它们。
  • (1) -> (2)(3) -> (2)分别由(3)(1)runtime.sendMessage()tabs.sendMessage()发送。它们会尽快收到,因为 background/event JS 是持久的(我不太确定这是否是正确的词,因为事件 JS 必须绑定到 eventListeners 中(。
  • (1) -> (3)(2) -> (3)tabs.sendMessage()发送。它们会尽快收到,因为只要网页处于活动状态,内容脚本就处于活动状态(因为它存在于并行沙盒中(。
  • (*) -> (4)(4) -> (*)不能由chrome.*处理安全问题,但(3) -> (4)(4) -> (3)可以由window.postMessage()处理,因为它们都存在于网页的上下文中。

几件事我特别有疑问 - 第一个是,当然,如果我正确地描述了事情。其他是这些:

  • runtime.sendMessage()tabs.sendMessage() 之间的区别究竟是什么,决定了哪些 JS 实际上可以使用它们?
  • 消息是如何传递的?调用*.sendMessage()window.postMessage()时,后台会发生什么?
  • Javascript有四类:(1)绑定到弹出窗口的JS,(2)在后台运行或作为事件运行的JS,在内容脚本中(3) JS,以及注入到页面中的(4) JS。

(1)(2)实际上是相同的("弹出窗口"也属于"扩展代码" - 请参阅浏览器操作、后台脚本和 chrome 扩展程序的内容脚本之间的通信上下文和方法?

  • (2) -> (1)(3) -> (1)runtime.sendMessage()发送。仅当弹出窗口打开时,才会收到它们。
  • (1) -> (2)(3) -> (2)分别由(3)(1)runtime.sendMessage()tabs.sendMessage()发送。它们会尽快收到,因为 background/event JS 是持久的(我不太确定这是否是正确的词,因为事件 JS 必须绑定到 eventListeners 中(。

runtime.sendMessage确实可以通过(1)(2)(3)发送。在接收者的角色中,(1)(2)之间没有特殊区别。以下是我对脚本的分类:chrome.runtime.sendMessage发送的消息通过扩展代码接收,但发件人的帧除外。例如,如果您在后台页面中放置一个<iframe>并从后台页面调用chrome.runtime.sendMessage,则将在该帧中触发chrome.runtime.onMessage

使用事件页面

时,只有在等待事件页面加载后才会调度消息事件。

  • (1) -> (3)(2) -> (3)tabs.sendMessage()发送。它们会尽快收到,因为只要网页处于活动状态,内容脚本就处于活动状态(因为它存在于并行沙盒中(。

只要您拥有有效的选项卡 ID,chrome.tabs.sendMessage就有意义。由于后台页面没有选项卡 ID,因此无法使用 tabs.sendMessage 向后台页面发送消息。内容脚本、选项卡中的扩展页面、选项卡中的扩展框架都可以接收由 chrome.tabs.sendMessage 发送的消息,因为它们是选项卡的一部分。

  • (*) -> (4)(4) -> (*)不能由chrome.*处理安全问题,但(3) -> (4)(4) -> (3)可以由window.postMessage()处理,因为它们都存在于网页的上下文中。

(4) -> (1,2)(网页到扩展代码(可以通过externally_connectable实现。

(4) -> (4)也可以使用 window.postMessage ,但不能直接使用 *.sendMessage(因为这不包括发送者(。

  • runtime.sendMessage()tabs.sendMessage()之间的区别究竟是什么,决定了哪些JS实际上可以使用它们?

tabs.sendMessage只能在选项卡 API 可用时使用,以向选项卡发送消息,而内容脚本也可以使用runtime.sendMessage

简而言之,使用 tabs.sendMessage 将消息发送到选项卡,使用 runtime.sendMessage 将消息发送到扩展的其他部分。

  • 消息是如何传递的?调用*.sendMessage()window.postMessage()时,后台会发生什么?
  • window.postMessage只有一个接收器,即message事件只调用一次。 *.sendMessage有零个或多个接收器(如果使用 tabs.sendMessage ,则可以通过设置 frameId 参数将其限制为一个(,因此可以多次调用chrome.runtime.onMessage(每帧一次(。

  • 如果不小心,可能会通过 window.postMessage 意外将信息泄露给不受信任的脚本。确保在两个方向(从网页到网页(上验证所有消息 - 有关更多信息,请参阅 MDN 上的 Window.postMessage#安全问题文章。 *.sendMessage仅在扩展中传递消息,因此通常是安全的。

  • *.sendMessage消息都是 JSON 序列化的,这比 postMessage 使用的结构化克隆算法受到的限制要大得多。

  • *.sendMessage始终需要至少两条 IPC 消息(发送到浏览器进程,浏览器进程到每个接收方(。 postMessage可以更有效地处理,因为消息是在同一渲染器进程中处理的。
    这是一个内部实现细节,不保证将来成立。在实践中,这意味着如果您发送大量数据并分析性能,那么您很可能会观察到*.sendMessage问题多于window.postMessage问题(对于单方面的基准测试,请参阅例如,对于内容脚本和 Chrome 扩展程序的背景页面之间的消息传递,是否有 32 字节或 64Bytes 这样的大小限制?

  • *.sendMessage(any message, optional function responseCallback)在内部实现为等效于调用chrome.runtime.connect(或chrome.tabs.connect(,使用 port.onMessage.addListener 注册responseCallback,然后断开端口连接(如果未设置回调,则立即断开连接,否则仅在调用回调后(。

    window.postMessage对消息进行排队。队列不会立即耗尽,但消息事件会"尽快"调度。