我正在开发一个带有清单的Chrome扩展程序,目前可以访问所有主机。后台脚本将内容脚本注入所有帧。加载DOM后,首页/框架中的内容脚本开始遍历DOM树。当walker遇到iframe时,它需要发送与该iframe窗口相关联的特定内容脚本(可能是跨源)以开始它的工作并包含一些带有此消息的序列化数据。父窗口暂停执行并等待孩子完成它的步行并发回消息,它与序列化数据一起完成。然后父母继续工作。我尝试了两种解决这个问题的方法:
frameElement.contentWindow.postMessage
:这在大多数情况下有效,但并非总是如此。有时,与iframe窗口关联的内容脚本消息事件侦听器永远不会收到该消息。我无法确认原因,但我认为在听众呼叫event.stopImmediatePropagation()
之前是听众。例如,在yahoo主页(https://www.yahoo.com)上,当向与iframe源https://s.yimg.com/rq/darla/2-9-9/html/r-sf.html关联的内容脚本发布消息时,永远不会收到消息。这是与广告相关的iframe。也许阻止消息是故意的。邮件发布时没有错误,我使用的是targetOrigin“*”。chrome.runtime.sendMessage
:我可以向后台页面发送消息,但无法弄清楚如何告诉后台页面中继消息的帧。父窗口内容脚本不知道与在DOM漫游中遇到的子帧元素关联的chrome扩展frameId。所以它无法告诉后台页面如何指导消息。对于第2点,我尝试了两种在stackoverflow上找到的技术:
window.frames
数组中的位置,并使用此索引将消息发布到后台页面。后台页面将消息发布到消息数据中具有所需索引的所有帧。只有在window.parent.frames数组中找到它的窗口对象位置的iframe才能匹配从消息中收到的索引,并继续它的行走。这工作正常,但在异步消息传递过程中容易受到window.frames
数组中的更改的影响(如果在发送消息后删除了iframe,则索引值可能不再与所需的帧匹配)。frameElement.name
。使用相同的消息传递技术,将名称发送到子iframe以与其window.name
值进行比较。我相信window.name
在iframe元素创建时从frameElement.name
获取它的值。但是,由于我不控制框架元素的创建,因此name属性通常是一个空字符串,不能依赖它来将iframe元素唯一地匹配到它们的窗口。有没有办法让我可靠地向与DOM树中的iframe元素关联的内容脚本发送消息?
答案 0 :(得分:6)
当您从内容脚本调用chrome.runtime.sendMessage
时,chrome.runtime.onMessage
侦听器(“发件人”)的第二个参数包含属性url
和frameId
。
您可以使用chrome.tabs.sendMessage
使用给定frameId
向特定框架发送消息(从扩展程序页面,例如背景页面)。
如果您想随时知道所有帧的列表(及其帧ID),请使用chrome.webNavigation.getAllFrames
。如果这样做,那么您可以在选项卡中构建一个框架树,然后将此信息发送到所有框架以供进一步处理。
postMessage
/ onMessage
之前是听众
frameElement.contentWindow.postMessage
:这大部分时间都有效,但并非总是如此。有时,与iframe窗口关联的内容脚本消息事件侦听器永远不会收到该消息。我无法确认原因,但我认为在听众调用event.stopImmediatePropagation()
可以通过在"run_at":"document_start"
运行脚本并立即注册message
事件侦听器来解决此问题。然后,您的处理程序将始终首先被调用,页面无法通过event.stopImmediatePropagation()
取消它。但是,不要盲目信任来自其他帧的信息并始终验证消息(例如,通过后台页面与其他帧通信)。
第一种方法提供了一种在帧之间交换数据的安全方法,但没有提供将帧链接到特定DOM元素的通用方法。
第二种方法允许您定位特定的(i)框架元素,但任何网页都可以这样做,因此该方法本身并不可靠。
通过组合两者,您将获得一个链接到DOM元素的安全通信通道。
这是应用上述方法在帧A和B之间进行通信的基本示例:
A:
中的内容脚本背景页面:
crypto.getRandomValues
)。frameId
的映射(以及来自A的消息中包含的其他信息)。A:
中的内容脚本postMessage
并传递 R 。B中的内容脚本:
注意:对于坚如磐石的应用程序,您需要考虑在任何这些步骤中删除框架的事实。如果忽略此过程的异步性质,可能会使应用程序处于不一致状态。