从chrome扩展程序访问iframe

Kir*_*lev 11 javascript iframe google-chrome-extension

我正在开发一个镀铬扩展,并遇到了一个大问题.

我正在使用内容脚本在网站上注入我的javascript代码.该网站有一个iframe.我可以更改iframe的源代码,但似乎无法访问iframe的contentWindow属性.我需要它在当前的carret位置插入文本.

所以基本上这个代码在页面的上下文中完美地工作:

$("#iframe1").contentWindow.document.execCommand("InsertHTML", false, 'test text');
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试在我的chrome扩展程序的上下文中运行时,我收到此错误:

TypeError: Cannot read property 'document' of undefined
Run Code Online (Sandbox Code Playgroud)

奇怪的是,我可以访问iframe的html.所以这段代码完全可以从chrome扩展程序中运行:

$("#iframe1").contents().find('div').html('test')
Run Code Online (Sandbox Code Playgroud)

我尝试在清单文件中放入"all_frames":true但没有运气:(

Rob*_*b W 19

要理解为什么你的代码不起作用,我将包含我之前答案的一个片段:

内容脚本无权访问页面的全局window对象.对于内容脚本,以下内容适用:

  • window变量没有指向页面的全局对象.相反,它指的是新的上下文,页面上的"层".页面的DOM完全可访问.#执行环境

鉴于一份文件包括   <iframe id="frameName" src="http://domain/"></iframe>:

  • 对框架内容的访问受到页面的相同原始策略的限制; 您的扩展程序的权限不会放松该政策.
  • frames[0]并且frames['frameName'],(通常指的是包含全局window对象的框架)是undefined.
  • var iframe = document.getElementById('frameName');
    • iframe.contentDocument返回document包含框架的对象,因为内容脚本可以访问页面的DOM.此属性null适用于同源策略.
    • iframe.contentDocument.defaultView(指window与文档关联的对象)未定义.
    • iframe.contentWindow不确定的.

同源帧的解决方案

在您的情况下,以下任何一种都可以工作:

// jQuery:
$("#iframe1").contents()[0].execCommand( ... );

// VanillaJS
document.getElementById("iframe1").contentDocument.execCommand( ... );

// "Unlock" contentWindow property by injecting code in context of page
var s = document.createElement('script');
s.textContent = 'document.getElementById("iframe1").contentWindow.document.execCommand( ... );';
document.head.appendChild(s);
Run Code Online (Sandbox Code Playgroud)

通用解决方案

通用解决方案"all_frames": true在清单文件中使用,并使用以下内容:

if (window != top) {
    parent.postMessage({fromExtension:true}, '*');
    addEventListener('message', function(event) {
        if (event.data && event.data.inserHTML) {
            document.execCommand('insertHTML', false, event.data.insertHTML);
        }
    });
} else {
    var test_html = 'test string';
    // Explanation of injection at https://stackoverflow.com/a/9517879/938089 :
    // Run code in the context of the page, so that the `contentWindow`
    //  property becomes accessible
    var script = document.createElement('script');
    script.textContent = '(' + function(s_html) {
        addEventListener('message', function(event) {
            if (event.data.fromExtension === true) {
                var iframe = document.getElementById('iframe1');
                if (iframe && (iframe.contentWindow === event.source)) {
                    // Window recognised, post message back
                    iframe.contentWindow.postMessage({insertHTML: s_html}, '*');
                }
            }
        });
    } + ')(' + JSON.stringify(test_html) + ');';
    (document.head||document.documentElement).appendChild(script);
    script.parentNode.removeChild(script);
}
Run Code Online (Sandbox Code Playgroud)

此演示仅用于教育目的,请勿在真实扩展中使用此演示.为什么?因为它用于postMessage传递消息.这些事件也可以由客户端生成,这会导致安全漏洞(XSS:任意HTML注入).

另一种选择postMessage是Chrome的消息API.有关演示,请参阅此答案.您将无法比较window对象.你可以做的是依靠window.name财产.该window.name属性会自动设置为iframe name属性的值(加载iframe时只需一次).