javascript - 阻止由 Chrome 扩展中的 onBeforeNavigate 事件指示的导航,但不阻止非导航请求

标签 javascript google-chrome google-chrome-extension

我想将浏览器限制在一组 URL 内。我在用着:

chrome.webNavigation.onBeforeNavigate.addListener(functon(details){
    if (notAllowed(details.url)) {
         // Do something to stop navigation
    }
});

我知道我可以取消chrome.webRequest.onBeforeRequest .但是,我不想阻止请求,例如 XHR 或任何其他请求。我希望此过滤器仅适用于导航。

对于用户来说,链接(例如 <a href="http://...">foo</a> )点击事件应该是停止的。

最佳答案

以下扩展添加了一个监听器到 webNavigation.onCompleted用于记住由 tabId 索引的 frameId==0 中的最新 URL触发事件的对象,以及之前的 URL。

一个监听器被添加到 webNavigation.onBeforeNavigate它监视匹配的 URL,在本例中为 stackexchange.com .如果 URL 匹配,则通过 tabs.update 更新选项卡 URL , 导航回最后一个有 webNavigation.onCompleted 的 URL事件被触发。

如果 onBeforeNavigate事件适用于 frameId除了 0 ,然后选项卡将导航到上一个 URL,其中 onCompletedframeId==0 触发了事件.如果先前的 URL 没有被使用,那么我们可能会进入一个循环,由于其中一个帧中的 URL 与我们阻止的 URL 匹配,当前 URL 会重复重新加载。处理此问题的更好方法是注入(inject)内容脚本以更改 src框架的属性。然后我们需要处理帧内的帧。

block 导航.js:

//Remember tab URLs
var tabsInfo = {};
function completedLoadingUrlInTab(details) {
    //console.log('details:',details);
    //We have completed loading a URL.
    createTabRecordIfNeeded(details.tabId);
    if(details.frameId !== 0){
        //Only record inforamtion for the main frame
        return;
    }
    //Remember the newUrl so we can check against it the next time
    //  an event is fired.
    tabsInfo[details.tabId].priorCompleteUrl = tabsInfo[details.tabId].completeUrl;
    tabsInfo[details.tabId].completeUrl = details.url;
}

function InfoForTab(_url,_priorUrl) {
    this.completeUrl = (typeof _url !== 'string') ? "" : _url;
    this.priorCompleteUrl = (typeof _priorUrl !== 'string') ? "" : _priorUrl;
}

function createTabRecordIfNeeded(tabId) {
    if(!tabsInfo.hasOwnProperty(tabId) || typeof tabsInfo[tabId] !== 'object') {
        //This is the first time we have encountered this tab.
        //Create an object to hold the collected info for the tab.
        tabsInfo[tabId] = new InfoForTab();
    }
}


//Block URLs
function blockUrlIfMatch(details){
    createTabRecordIfNeeded(details.tabId);
    if(/^[^:/]+:\/\/[^/]*stackexchange\.[^/.]+\//.test(details.url)){
        //Block this URL by navigating to the already current URL
        console.log('Blocking URL:',details.url);
        console.log('Returning to URL:',tabsInfo[details.tabId].completeUrl);
        if(details.frameId !==0){
            //This navigation is in a subframe. We currently handle that  by
            //  navigating to the page prior to the current one.
            //  Probably should handle this by changing the src of the frame.
            //  This would require injecting a content script to change the src.
            //  Would also need to handle frames within frames. 
            //Must navigate to priorCmpleteUrl as we can not load the current one.
            tabsInfo[details.tabId].completeUrl = tabsInfo[details.tabId].priorCompleteUrl;
        }
        var urlToUse = tabsInfo[details.tabId].completeUrl;
        urlToUse = (typeof urlToUse === 'string') ? urlToUse : '';
        chrome.tabs.update(details.tabId,{url: urlToUse},function(tab){
            if(chrome.runtime.lastError){
                if(chrome.runtime.lastError.message.indexOf('No tab with id:') > -1){
                    //Chrome is probably loading a page in a tab which it is expecting to
                    //  swap out with a current tab.  Need to decide how to handle this
                    //  case.
                    //For now just output the error message
                    console.log('Error:',chrome.runtime.lastError.message)
                } else {
                    console.log('Error:',chrome.runtime.lastError.message)
                }
            }
        });
        //Notify the user URL was blocked.
        notifyOfBlockedUrl(details.url);
    }
}

function notifyOfBlockedUrl(url){
    //This will fail if you have not provided an icon.
    chrome.notifications.create({
        type: 'basic',
        iconUrl: 'blockedUrl.png',
        title:'Blocked URL',
        message:url
    });
}


//Startup
chrome.webNavigation.onCompleted.addListener(completedLoadingUrlInTab);
chrome.webNavigation.onBeforeNavigate.addListener(blockUrlIfMatch);

//Get the URLs for all current tabs when add-on is loaded.
//Block any currently matching URLs.  Does not check for URLs in frames.
chrome.tabs.query({},tabs => {
    tabs.forEach(tab => {
        createTabRecordIfNeeded(tab.id);
        tabsInfo[tab.id].completeUrl = tab.url;
        blockUrlIfMatch({
            tabId : tab.id,
            frameId : 1, //use 1. This will result in going to '' at this time.
            url : tab.url
        });

    });
});

list .json:

{
    "description": "Watch webNavigation events and block matching URLs",
    "manifest_version": 2,
    "name": "webNavigation based block navigation to matched URLs",
    "version": "0.1",
    "permissions": [
        "notifications",
        "webNavigation",
        "tabs"
    ],
    "background": {
        "scripts": ["blockNavigation.js"]
    }
}

关于javascript - 阻止由 Chrome 扩展中的 onBeforeNavigate 事件指示的导航,但不阻止非导航请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39333408/

相关文章:

html - 将显示表 : working on Firefox, 的 4 个单元格集中在一起在 Chrome 上不起作用

javascript - 如何让z-index=-1的元素接收点击事件?

javascript - 是什么让 Date 构造函数接受 momentjs 对象?

javascript - 单击页面上的任意位置时如何从元素中删除类?

javascript - 如何在 chrome 中创建一个固定在顶部的工具栏并让所有固定元素正常工作

google-chrome-extension - Chrome 中的自定义协议(protocol)处理程序

mysql - 如何通过扩展程序在 Gmail 中创建新按钮/功能?

javascript - ReactJS 将元素拥有的 prop 传递给函数

html - 列表样式图像不适用于 chrome 中的 gmail

python - Selenium...程序适用于 Firefox,但不适用于 Chrome