【问题标题】:Impossible to load an iframe inside the background page (status=canceled)无法在后台页面中加载 iframe(状态=已取消)
【发布时间】:2017-03-16 05:59:55
【问题描述】:

我想在后台页面中动态注入和加载 iframe。但是每次请求都会被取消。

http://i.imgur.com/Puto33c.png

这曾经在一周前起作用。我不知道我错在哪里。

为了重现这个问题,我创建了一个小扩展:

manifest.js:

{
    "name": "iframe background",
    "version": "1.0.0",
    "manifest_version": 2,

    "browser_action": {
        "default_title": "iframe"
    },

    "background": {
        "persistent": false,
        "scripts": ["background.js"]
    }
}

background.js:

chrome.browserAction.onClicked.addListener(function() {
    var iframe = document.createElement('iframe');
    iframe.src = 'http://localhost:3000/';
    iframe.onload = function() {
        console.log(iframe.contentDocument); // return null
    };
    document.body.appendChild(iframe);
});

要加载的页面未被 X-Frame-Options SAMEORIGIN 阻止。

我尝试将 iframe 直接放在 HTML 背景页面中,但没有成功。

我还尝试添加 content_security_policy : "content_security_policy": "script-src 'self'; object-src 'self'; frame-src 'self' http://localhost:3000/"

但 iframe 仍然无法加载。

有人对此问题有解决方法或解决方案吗?

谢谢!

【问题讨论】:

    标签: iframe google-chrome-extension


    【解决方案1】:

    Chrome 58.0.3014.0 enables Site Isolation for extensions by default 使 iframe 加载到由单独的 chrome.exe 操作系统进程处理的不同渲染器进程中。

    “已取消”消息意味着扩展程序的 chrome.exe 进程取消了请求,并由另一个隐藏的 chrome.exe 进程处理。

    正确的方法是声明一个内容脚本,该脚本将自动在 iframe URL 上运行并与后台页面通信。注意:只能传递 JSON-fiable 数据,换句话说,您可以传递 innerHTML 但不能传递 DOM 元素。这很容易通过 DOMParser 处理。

    manifest.json 添加:

    "content_scripts": [{
        "matches": ["http://localhost:3000/*"],
        "js": ["iframe.js"],
        "run_at": "document_end",
        "all_frames": true
    }],
    

    iframe.js:

    var port = chrome.runtime.connect();
    // send something immediately
    port.postMessage({html: document.documentElement.innerHTML});
    
    // process any further messages from the background page
    port.onMessage.addListener(msg => {
        ..............
        // reply
        port.postMessage(anyJSONfiableObject); // not DOM elements!
    });
    

    background.js:

    var iframePort;
    
    chrome.browserAction.onClicked.addListener(() => {
        document.body.insertAdjacentHTML('beforeend',
            '<iframe src="http://localhost:3000/"></iframe>');
    });
    
    chrome.runtime.onConnect.addListener(port => {
        // save in a global variable to access it later from other functions
        iframePort = port;
    
        port.onMessage.addListener(msg => {
            if (msg.html) {
                const doc = new DOMParser().parseFromString(msg.html, 'text/html');
                console.log(doc);
                alert('Received HTML from the iframe, see the console');
            }
        });
    });
    

    另请参阅类似的 QA:content.js in iframe from chrome-extension popup

    【讨论】:

    • 有什么简单的方法可以在 Chrome 扩展中使用github.com/zendesk/cross-storage 吗?跨存储隐式创建&lt;iframe src="http://example.com/hub"&gt;,并提供API将数据写入&lt;iframe&gt;的localStorage。
    • 跨存储似乎开箱即用,尽管其 &lt;iframe&gt; 为红色,(cancelled) 在网络选项卡中。
    • 为什么您需要一个库来实现只需在此答案中显示的模板中添加几行代码即可实现的功能?另外,我不知道有什么方法可以使用该库,因为我还没有尝试过。
    • 您的解决方案的一个缺点是内容脚本不仅会被注入到背景页面内的&lt;iframe&gt;,而且会被注入到具有相同 URL 的所有选项卡和 iframe(例如 example.com/hub)中。跨度>
    • 确实如此。您可以检查if (window != top),只有在这种情况下才能继续。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 2021-09-02
    • 2012-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多