仅在用户单击链接打开时重定向新选项卡/窗口之前,防止初始webRequest

时间:2016-12-13 22:00:06

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

我正在开发Chrome扩展程序。我想要完成的是重定向在新窗口或新选项卡中打开的超链接。我已尝试使用下面的代码,虽然这会重定向选项卡,但它不会阻止提交原始页面请求,这也是我想要完成的事情。

chrome.webNavigation.onCreatedNavigationTarget.addListener(function(details) {
    chrome.tabs.update(details.tabId, {
        url: 'http://www.google.com/'
    });
});

如果用户在新窗口中打开超链接(例如,shift / ctrl + click,中键,上下文菜单等),我只想重定向。如果窗口或标签因其他原因而被打开,我不想重定向。

2 个答案:

答案 0 :(得分:1)

重定向仅由 链接打开的新标签/窗口,但不能直接

不幸的是,如果没有每个页面中的内容脚本,在传输webRequest之前,您无法区分用户单击链接以及打开新选项卡或窗口的其他原因。

导致选项卡或窗口打开的webNavigation类型由transitionType属性的值明确指示,在提供给webNavigation.onCommitted侦听器的详细信息中。如果是来自用户点击链接,则transitionType属性的值为link。如果请求来自链接,则不是webNavigation.onCommitted事件之前通常可用于背景页面的信息。

不幸的是,根据您的需要,webNavigation.onCommitted事件在页面网址的webRequest完成后触发。因此,如果没有某种方式可以提前知道转换是用户单击链接的结果(例如使用内容脚本),则您无法知道当前转换是用户及时点击链接的结果选择将webRequest重定向到页面的主URL。

您可以做的是始终将初始请求重定向到about:blank。然后,一旦您收到webNavigation.onCommitted事件,您就可以根据transitionType属性的值进行选择,将标签的网址更改为您最终想到的重定向网址,或将其更改回原始目标页面的URL。此过程将导致丢失表示单击链接的页面的Referer标题。

显然,您可以使用最终目的地而不是about:blank。这可能会更好,但即使选项卡最终被放回原始目标网址,也会导致对该网址的webRequest。

以下代码将执行上述操作:

background.js

var tabsBlockedOnce = new Set();
var tabsRedirected = new Map();
chrome.webRequest.onBeforeRequest.addListener(function(details){
    if(!tabsBlockedOnce.has(details.tabId)){
        tabsBlockedOnce.add(details.tabId);
        tabsRedirected.set(details.tabId,details.url);
        //Redirect
        return {redirectUrl:'about:blank'};
        //Block
        //return {cancel:true};
    }
},{urls:['<all_urls>'],types:['main_frame']},['blocking']);

chrome.webNavigation.onCommitted.addListener(function(details){
    if(tabsRedirected.has(details.tabId)){
        //Default is to not redirect
        let url = tabsRedirected.get(details.tabId);
        tabsRedirected.delete(details.tabId);
        if(details.transitionType === 'link'){
            //It was a link, go to where we want to redirect.
            url = 'http://www.google.com/'; 
        }
        //Send the tab where it is supposed to go
        chrome.tabs.update(details.tabId,{url:url});
    }
});

//Don't block the first request in any tab that already exists.
//  This is of primary benefit when the extension is first installed/reloaded.
chrome.tabs.query({},function(tabs){
    tabs.forEach(function(tab){
        tabsBlockedOnce.add(tab.id);
    });
});

manifest.json (部分):

"permissions": [
    "webNavigation",
    "webRequest",
    "webRequestBlocking"
],
"background": {
    "scripts": ["background.js"]
}

每个页面都有一个内容脚本,您可以直接执行

为了直接执行此操作(即,如果页面最终不会被重定向,则不会干扰原始webRequest),您必须知道webRequest的原因是在{之前点击了链接{1}}事件触发。要及时将此信息提供给后台脚本,您必须在每个页面中注入一个内容脚本,并webRequest.onBeforeRequest向您的后台脚本发送一条消息,指出链接正在被点击。

根据测试,这样的消息将在runtime.sendMessage()解雇之前到达后台脚本。能够使用内容脚本执行此操作取决于发送带有webRequest.onBeforeRequest的消息的内容脚本与runtime.sendMessage()事件触发时间与runtime.onMessage时间之间的异步通信的确切时间事件火灾。测试表明webRequest.onBeforeRequestmousedownmouseup事件(click并非总是针对所有鼠标按钮触发)可以发送后台脚本在{之前“接收的消息{1}}事件触发。此时间无法保证,但似乎有效。

从用户体验的角度来看,这通常是一个坏主意

您希望做的是篡夺用户选择使用UI交互来专门打开新标签页或窗口中的链接。除非我专门寻找这个功能,否则我会发现这个非常很烦人,而且几乎可以肯定会立即卸载扩展程序。篡夺用户的代理机构来控制他们的机器是应该在非常有限的情况下进行的。除非您处于专业环境中,否则您提出的建议将违背大多数用户的期望。此外,它可能会破坏与某些网站的互动。

答案 1 :(得分:0)

我肯定不知道这一点,但是你不必取消本机活动而支持你想做的事情,类似于event.preventDeafult()