Chrome 扩展消息传递架构

Chrome Extension Messaging Architecture

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

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

有几件事我有具体的疑问 - 第一个当然是,如果我已经正确描述了事情。其他的是这些:

  • There are four classes of Javascript: (1) JS tied to the popup, (2) JS running in the background or as an event, (3) JS in content scripts, and (4) JS injected into the page.

(1)(2) 实际上是相同的("popup" 也属于 "extension code" - 参见 Contexts and methods for communication between the browser action, background scripts, and content scripts of chrome extensions?)。

  • (2) -> (1) and (3) -> (1) are sent by runtime.sendMessage(). They're only received when the popup is open.
  • (1) -> (2) and (3) -> (2) are sent by runtime.sendMessage() or tabs.sendMessage() from (3) and (1) respectively. They're received ASAP, because background/event JS is persistent (I'm not quite sure if that's the right word, since event JS has to be tied into eventListeners).

runtime.sendMessage确实可以被(1)(2)(3)发送。在接收者的角色上,(1)(2)并没有什么特别的区别。这里是 my classification of scripts 进来的地方: chrome.runtime.sendMessage 发送的消息由扩展代码接收,除了发件人的帧。例如,如果您在后台页面中放置一个 <iframe> 并从后台页面调用 chrome.runtime.sendMessage,则将在该框架中触发 chrome.runtime.onMessage

使用 event pages 时,仅在等待事件页面加载后才调度消息事件。

  • (1) -> (3) and (2) -> (3) are sent by tabs.sendMessage(). They're received ASAP, since the content script is active as long as the webpage is (since it exists in a parallel sandbox).

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

  • (*) -> (4) and (4) -> (*) can't be handled by chrome.* for security issues, but (3) -> (4) and (4) -> (3) can be handled by window.postMessage(), since they both exist within the context of the webpage.

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

并且(4) -> (4)也可以用window.postMessage,但不能直接用*.sendMessage(因为这不包括发件人)。

  • What exactly is the distinction between runtime.sendMessage() and tabs.sendMessage() that dictates which JS can actually use them?

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

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

  • How do messages get passed around? What happens in the background when *.sendMessage() or window.postMessage() is called?
  • window.postMessage 只有一个接收器,即 message event is called only once. *.sendMessage has zero or more receivers (if you use tabs.sendMessage, then you can restrict this to one by setting the frameId parameter), so chrome.runtime.onMessage 可以被多次调用(每帧一次)。

  • 如果不小心,可能会通过 window.postMessage 不小心将信息泄露给不受信任的脚本。确保您在两个方向(从网页和到网页)验证所有消息 - 请参阅 Window.postMessage#Security concerns article on MDN 了解更多信息。 *.sendMessage 仅在您的扩展程序内传递消息,因此通常是安全的。

  • *.sendMessage 消息是 postMessage 使用的 JSON-serialized, which is much more restricted than the structured cloning algorithm

  • *.sendMessage 总是需要至少两个 IPC messages(发送者到浏览器进程,浏览器进程到每个接收者)。 postMessage 可以更有效地处理,因为消息是在同一个渲染器进程中处理的。
    这是一个内部实施细节,不保证将来会保留。这在实践中意味着,如果您发送大量数据并分析性能,那么您很可能会观察到 *.sendMessagewindow.postMessage 更多的问题(对于单方面基准,请参见例如).

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

    window.postMessagequeues a message。队列不会立即耗尽,但会调度消息事件 "as soon as possible".