为什么Firefox不允许您在主框架中执行脚本?

时间:2016-07-26 21:50:23

标签: javascript google-chrome-extension firefox-webextensions

我正在使用基于Chrome的Firefox新的webExtensions框架编写webextension。所有示例扩展都在Nightly版本中工作,因此我可以在其中进行测试。我尝试做的是在加载时在内容页面上运行脚本。这是我的background.js页面:

background.js

        final List<GbGroup> groups = this.businessService.getSiteSectionsAndGroups();

        toolbar.add(new EmptyPanel("groupFilterOnlyOne").setVisible(false));

        // add the default ALL group to the list
        String allGroupsTitle = getString("groups.all");

        groups.add(0, new GbGroup(null, allGroupsTitle, null, GbGroup.Type.ALL));

        final DropDownChoice<GbGroup> groupFilter = new DropDownChoice<GbGroup>("groupFilter", new Model<GbGroup>(),
                groups, new ChoiceRenderer<GbGroup>() {
            private static final long serialVersionUID = 1L;

            @Override
            public Object getDisplayValue(final GbGroup g) {
                return g.getTitle();
            }

            @Override
            public String getIdValue(final GbGroup g, final int index) {
                return g.getId();
            }

        });

        groupFilter.add(new AjaxFormComponentUpdatingBehavior("onchange") {
            @Override
            protected void onUpdate(final AjaxRequestTarget target) {

                final GbGroup selected = (GbGroup) groupFilter.getDefaultModelObject();

                // store selected group (null ok)
                final GradebookUiSettings settings = g_Page.getUiSettings();
                settings.setGroupFilter(selected);
                g_Page.setUiSettings(settings);

            }
        });

这适用于Nightly。我从后台页面获得了一系列详细信息(&#34;详细信息是......&#34;)以及几行&#34; ok&#34;在内容页面的控制台上,每个资源加载一个。它在Chrome中运行相同(清单文件略有不同)。

我想要的是第二种变体,它只在页面上运行一次。这在Chrome中运行良好。在Nightly中,它显示了一个&#34;细节&#34;来自主框架的消息,但内容页面上的控制台中没有任何内容。

我确定这是一个时间问题,但这里有什么问题?

manifest.json (删除&#34;应用&#34;:{...}与Chrome一起使用)

"use strict";

function onCompletedFunc(details) {
    var script = 'console.log("ok");';
    console.log("Details are %o", details);
    chrome.tabs.executeScript(details['tabId'], {
        code: script,
        runAt: 'document_end'
    });
};
chrome.webRequest.onCompleted.addListener(onCompletedFunc, 
                                     {'urls': ['<all_urls>']}, 
                                     ['responseHeaders']);
//Does not work:
/*
chrome.webRequest.onCompleted.addListener(onCompletedFunc, 
                                     {'urls': ['<all_urls>'], 'types':["main_frame"]}, 
                                     ['responseHeaders']);
*/

1 个答案:

答案 0 :(得分:1)

您的第一个代码段(不包含types)仅适用,因为您不仅要获取main_frame的请求,还要获取另一个子资源。如果要注入脚本,webRequest.onCompleted不是正确的事件。无法保证选项卡中的页面与您收到请求的页面匹配。

如果您想无条件地运行代码,只需在清单文件中声明内容脚本即可。有关详细信息,请参阅content script documentation

如果必须使用编程注入,请使用chrome.webNavigation.onCommitted事件而不是webRequest事件。通过此事件,您知道该选项卡现在显示对给定URL的响应。例如:

chrome.webNavigation.onCommitted.addListener(function(details) {
    // Example: Only run in main frame and URLs containing "example"
    if (details.frameId === 0 && details.url.includes('example')) {
        chrome.tabs.executeScript(details.tabId, {
            code: 'console.log("Injected at " + document.URL);',
            runAt: 'document_end'
        });
    }
});
// filter (the second parameter, not used above) is supported as of Firefox 50.

如果您使用webNavigation.onCommitted必须考虑到API是非阻止的,则会发生事件。可能(但概率很低)发生以下情况:

  1. 用户启动请求。
  2. webNavigation.onCompleted开火。
  3. 您调用tabs.executeScript
  4. 同时,标签会导航到其他网站。
  5. tabs.executeScript请求到达选项卡,同时切换到不同的URL。
  6. 哎呀,你刚刚在一个与你想要的页面不同的页面中注入了一个脚本。
  7. 如果不希望网址不匹配,请在继续使用内容脚本逻辑之前检查document.URLlocation是否具有预期值。