重定向由仅链接打开的新标签页/窗口,而不是直接重定向
不幸的是,如果没有每个页面中的内容脚本,您无法在 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 事件触发之间的异步通信的确切时间。测试表明mousedown、mouseup 和click 事件(click 并不总是针对所有鼠标按钮触发)可以发送在webRequest.onBeforeRequest 事件触发之前后台脚本接收到的消息。此时间无法保证,但似乎可行。
从用户体验的角度来看,这通常是个坏主意
您想要做的事情会篡夺用户选择使用 UI 交互来专门在新选项卡或窗口中打开链接的选择。除非我专门寻找这个功能,否则我会觉得这非常很烦人,几乎可以肯定的是,我会立即卸载该扩展。篡夺用户的代理权来控制他们的机器是只有在非常有限的情况下才应该做的事情。除非您处于专业环境中,否则您提出的建议将与大多数用户的期望相反。此外,它可能会中断与某些网站的交互。