【问题标题】:Prevent initial webRequest prior to redirecting new tab/window only when opened by user clicking link仅当用户单击链接打开时,才在重定向新选项卡/窗口之前阻止初始 webRequest
【发布时间】:2016-12-13 22:00:05
【问题描述】:

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

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

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

【问题讨论】:

  • @Makyen 我更新了我的问题,不确定我到底在想什么。我不确定您对“此 Chrome 实例之外的任何信息”的意思。我只是不希望浏览器根据原始 URL 发送任何请求。
  • 您是否希望重定向那些由用户单击超链接创建的新标签/窗口(即不是所有新标签/窗口,而是 那些由用户点击链接创建的)?
  • @Makyen 我只想在用户在新窗口中打开超链接时重定向(例如 shift/ctrl+click、中键单击、上下文菜单等)

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


【解决方案1】:

重定向由链接打开的新标签页/窗口,而不是直接重定向

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

导致选项卡或窗口打开的 webNavigation 类型由 transitionType 属性的值清楚地指示,在提供给 webNavigation.onCommitted 侦听器的详细信息中。如果它来自用户单击链接,则transitionType 属性将具有link 的值。如果请求来自链接,则不是webNavigation.onCommitted 事件之前后台页面通常可用的信息。

不幸的是,正如您所愿,webNavigation.onCommitted 事件在页面 URL 的 webRequest 完成后触发。因此,如果无法提前知道转换是用户单击链接的结果(例如使用内容脚本),您将无法知道当前转换是用户及时单击链接以进行选择的结果重定向页面主 URL 的 webRequest。

您可以做的是总是将初始请求重定向到about:blank。然后,一旦您收到 webNavigation.onCommitted 事件,您可以根据 transitionType 属性的值做出选择,将选项卡的 URL 更改为您最终想到的重定向 URL,或者将其更改回 URL这是最初的预期页面。此过程将导致Referer 标头丢失,该标头代表单击链接的页面。

显然,您可以使用您的最终目的地而不是about:blank。这可能会更好,但即使选项卡最终被放回原始目标 URL,也会导致对该 URL 的 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 的原因是在@之前单击了链接987654334@ 事件触发。要及时将此信息发送到您的后台脚本,您必须在每个页面中注入一个内容脚本,并 runtime.sendMessage() 向您的后台脚本发送一条消息,说明链接正在被点击。

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

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

您想要做的事情会篡夺用户选择使用 UI 交互来专门在新选项卡或窗口中打开链接的选择。除非我专门寻找这个功能,否则我会觉得这非常很烦人,几乎可以肯定的是,我会立即卸载该扩展。篡夺用户的代理权来控制他们的机器是只有在非常有限的情况下才应该做的事情。除非您处于专业环境中,否则您提出的建议将与大多数用户的期望相反。此外,它可能会中断与某些网站的交互。

【讨论】:

    【解决方案2】:

    我不确定这一点,但您是否必须取消原生事件以支持您想要做的事情,类似于event.preventDeafult()

    【讨论】:

      猜你喜欢
      • 2013-08-10
      • 2010-12-01
      • 2019-06-01
      • 2021-09-21
      • 1970-01-01
      • 2011-11-05
      • 2014-02-23
      • 2013-02-15
      • 2019-08-23
      相关资源
      最近更新 更多