谷歌Chrome扩展:如何在页面重新加载后立即注入脚本? [英] Google chrome extension: how to inject script immediately after page reload?

查看:781
本文介绍了谷歌Chrome扩展:如何在页面重新加载后立即注入脚本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  var code ='window.location.reload()

我有一个后台脚本,可以定期重新加载当前标签。 ;';
chrome.tabs.executeScript(my_active_tab,{code:code});

在每次重新加载页面后,立即我要注入另一个脚本。

  chrome.tabs.onUpdated.addListener(function(tabId,changeInfo,tab){
if(changeInfo.status =='complete'){
chrome.tabs.executeScript(tabId,{file:my_script.js});
}
});

以上是我目前的代码。事情是,它可以工作,但速度太慢,因为它在每个图像加载完成后都会等待。



我的目标是在DOM加载后立即执行脚本。任何想法? 使用 manifest.json content_scripts manifest.json code $> $ <$ c $>使用 manifest.json content_scripts 使用run_at:document_start的条目是您唯一可以担保的方式您的内容脚本是在页面存在之前注入的。此时注入的代码将会发现 document.body document.head 将会是 null



使用 tabs.executeScript()



致力于 tabs.executeScript() 位于 webRequest.onHeadersReceived webNavigation之后触发的c $ c> 事件.onBeforeNavigate 事件可能会导致您感兴趣的页面导航。使用 tabs.executeScript()在脚本中没有被注入新页面而没有任何报告的错误。考虑到后台脚本和加载页面的过程之间固有的异步性,这类故障可能是间歇性的,并且会受OS /系统配置和正在加载的确切页面的影响。实际上,我的声明 webRequest.onHeadersReceived 将会基于测试,而不是在Chrome源代码中进行验证。因此,可能会出现一些我没有测试过的角落案例。

在这一点的注射一直有效,但注射发生的时间与页面加载有关有点不一致。有时, document.head document.body 将会是 null manifest.json content_scripts 注入 run_at:document_start ) 。其他时候, document.head document.body 将包含一个有效的DOM。它似乎没有可能让这个时间更紧张(即总是有 document.head document.body 由于后台脚本和内容位于不同的进程中,所以 null ),因此,本质上是异步的。



使用 webNavigation.onBeforeNavigate not 至少等待关联的 webRequest.onHeadersReceived 事件也是如此早期并且不起作用(内容脚本未被注入)。换句话说,即使关联的 webRequest.onSendHeaders 事件为时尚早。



很明显,为了尽早注入内容脚本,必须指定 runAt:'document_start' 在您的调用 tabs.executeScript()



在DOM存在之后注入: webNavigation.onCommitted



如果你想要一些更容易的东西,并且会导致内容脚本在除HTML主文档之外的任何页面之前被注入,那么你可以使用 webNavigation.onCommitted 事件来触发您的 tabs.executeScript()。这将导致注入的内容脚本被立即加载到主HTML文档之后。使用 webNavigation.onCommitted 变得更容易,因为它可以为您的事件指定过滤器。因此,您可以仅针对您感兴趣的URL调用事件侦听器。


$ b

webNavigation.onCommitted 事件在主HTML页面的 webRequest.ResponseStarted 事件之后触发,但在获取任何资源之前(即在任何 webRequest.BeforeRequest code>页面资源事件)。有趣的是,它在声明状态的 tabs.onUpdated 事件后触发:'loading'。使用 status:'loading' tabs.onUpdated 事件本身并不是一个好的触发器,因为它如果您只想要 tabs.executeScript,可以使用相同的属性激发其他原因,但不会显示页面加载/重新加载。 ()在页面上 reload

webNavigation.onCommitted 事件侦听器收到属性: transitionType ,根据原因将不同值的导航。其中一个值是'reload',您可以使用它来过滤页面重新加载。



你有兴趣在页面重新加载,而不是加载框架,你会希望确保 webNavigation 事件是为 frameId:0 $ b 这些是您通过点击重新加载此页面按钮重新加载标签时发生的事件:

  webNavigation.onBeforeNavigate  - > arg [0] = {frameId:0,parentFrameId:-1,processId:-1,tabId:411,timeStamp:1500401223978.314,url:http://www.example .com /} 
webRequest.onBeforeRequest - > arg [0] = {frameId:0,method:GET,parentFrameId:-1,requestId:260870,tabId:411,timeStamp:1500401223979.044, :main_frame,url:http://www.example.com/}
webRequest.onBeforeSendHeaders - > arg [0] = {frameId:0,method:GET,parentFrameId: - 1,requestHeaders:[{name:Upgrade-Insecure-Requests,value 1},{name:用户代理,值:Mozilla / 5.0(Windows NT 10.0; Win64; x64)AppleWebKit / 537.36(KHTML,像Gecko)Chrome / 59.0.3071.115 Safari / 537.36 },{ 名称: 接受, 值: text / html的,应用/ XHTML + xml的,应用/ XML; q = 0.9,图像/ WEBP,图像/ APNG,* / *; q = 0.8 },{name:Accept-Encoding,value:gzip,deflate},{name:Accept-Language,value:en-US,en; q = 0.8 }],requestId:260870,tabId:411,timeStamp:1500401223979.3242,type:main_frame,url:http://www.example.com/}
webRequest.onSendHeaders - > arg [0] = {frameId:0,method:GET,parentFrameId: - 1,requestHeaders:[{name:Upgrade-Insecure-Requests,value 1},{name:用户代理,值:Mozilla / 5.0(Windows NT 10.0; Win64; x64)AppleWebKit / 537.36(KHTML,像Gecko)Chrome / 59.0.3071.115 Safari / 537.36 },{ 名称: 接受, 值: text / html的,应用/ XHTML + xml的,应用/ XML; q = 0.9,图像/ WEBP,图像/ APNG,* / *; q = 0.8 },{name:Accept-Encoding,value:gzip,deflate},{name:Accept-Language,value:en-US,en; q = 0.8 }],requestId:260870,tabId:411,timeStamp:1500401223979.538,type:main_frame,url:http://www.example.com/}
webRequest.onHeadersReceived - > arg [0] = {frameId:0,method:GET,parentFrameId:-1,requestId:260870,responseHeaders:[{name:Content-Encoding 值: gzip的},{ 名称: 接受范围, 值: 字节},{ 名称: 缓存控制, 值:最大年龄= 604800},{name:Content-Type,value:text / html},{name:Date,value:2017年7月18日星期二18:07:03 GMT},{name:Etag,value:\359670651 \},{name:Expires,value:2017年7月25日星期二18:07 :03 GMT},{name:Last-Modified,value:Fri,2013年8月9日23:54:35 GMT},{name:Server,value: ECS(rhv / 818F)},{name:Vary,value:Accept-Encoding},{name:X-Cache,value:HIT}, name:Content-Length,value:606}],statusCode:200,statusLine:HTTP / 1.1 200 OK,tabId:411,timeStamp:1500401224072.296, type:main_frame,url:http://www.example.com/}
--- ^^^^^^^^^^^^^^^^^^ ^^^^^^^ - 最早的tabs.executeScript()注入位于webRequest.onHeadersReceived事件的处理程序中。
webRequest.onResponseStarted - > arg [0] = {frameId:0,fromCache:false,ip:93.184.216.34,method:GET,parentFrameId: - 1,requestId:260870 responseHeaders响应:[{ 名称: 内容编码, 值: gzip的},{ 名称: 接受范围, 值: 字节},{ 名 : 缓存控制, 值: 最大年龄= 604800},{ 名: 内容类型, 值: text / html的},{ 名: 日期 ,value:2017年7月18日18:07:03 GMT},{name:Etag,value:\359670651 \},{name: 2017年7月25日星期三18:07:03 GMT},{name:Last-Modified,value:星期五,2013年8月9日23时54分35秒GMT },{name:Server,value:ECS(rhv / 818F)},{name:Vary,value:Accept-Encoding},{name X-缓存, 值: 命中},{ 名称: 内容长度, 值: 606}], 的StatusCode:200, 状态行:HTTP / 1.1 200 OK,tabId:411,timeStamp:1500401224072.5032,type:main_frame,url:http://www.example.com/}
webRequest.onCompleted - > ; arg [0] = {frameId:0,fromCache:false,ip:93.184.216.34,method:GET,parentFrameId: - 1,requestId:260870 responseHeaders响应:[{ 名称: 内容编码, 值: gzip的},{ 名称: 接受范围, 值: 字节},{ 名 : 缓存控制, 值: 最大年龄= 604800},{ 名: 内容类型, 值: text / html的},{ 名: 日期 ,value:2017年7月18日18:07:03 GMT},{name:Etag,value:\359670651 \},{name: 2017年7月25日星期三18:07:03 GMT},{name:Last-Modified,value:星期五,2013年8月9日23时54分35秒GMT },{name:Server,value:ECS(rhv / 818F)},{name:Vary,value:Accept-Encoding},{name X-缓存, 值: 命中},{ 名称: 内容长度, 值: 606}], 的StatusCode:200, 状态行:HTTP / 1.1 200 OK,tabId:411,timeStamp:1500401224074.0261,type:main_frame,url:http://www.example.com/}
tabs.onUpdated - > ; arg [0] = 411 :: arg [1] = {status:loading,url:http://www.example.com/} :: arg [2] = {active :真 可听:假 autoDiscardable:, 丢弃 真:假, 高度:902, 突出显示:真, ID:411, 隐身:假, 指数:1 mutedInfo:{ 静音:假}, 固定:假的, 选择:真正的 状态: 装载, 称号: www.example.com, URL: http://www.example.com/\",\"width\":1282,\"windowId\":10}
tabs.onZoomChange - > arg [0] = {newZoomFactor:1,oldZoomFactor:1,tabId:411,zoomSettings:{mode:automatic,scope:per-origin}}
webNavigation.onCommitted - > arg [0] = {frameId:0,processId:107,tabId:411,timeStamp:1500401224079.4019,transitionQualifiers:[]transitionType:reloadurl http://www.example.com/}
--->>以下是您可以告诉它是重新加载的位置------------------ -------------------------------------------------- ------------------------------ ^^^^^^^^^^^^^^^^^^^^ ^^^^^
history.onVisited - > arg [0] = {id:42,lastVisitTime:1500401224077.579,title:示例域,typedCount:1,url:http://www.example.com/ ,visitCount:12}
tabs.onUpdated - > arg [0] = 411 :: arg [1] = {title:示例域} :: arg [2] = {active:true,audible:false,autoDiscardable:true,丢弃 :假, 高度 :902, 突出显示 :真, ID :411, 隐身 :假, 指数 :1, mutedInfo :{ 静音 :假}, 固定 :false,selected:true,status:加载,title:示例域,url:http://www.example.com/,width:1282, windowId:10}
webNavigation.onDOMContentLoaded - > arg [0] = {frameId:0,processId:107,tabId:411,timeStamp:1500401224093.404,url:http://www.example.com/}
webNavigation.on完成 - > arg [0] = {frameId:0,processId:107,tabId:411,timeStamp:1500401224094.768,url:http://www.example.com/}
tabs.onUpdated - > arg [0] = 411 :: arg [1] = {status:complete} :: arg [2] = {active:true,audible:false,autoDiscardable:true, :假, 高度 :902, 突出显示 :真, ID :411, 隐身 :假, 指数 :1, mutedInfo :{ 静音 :假}, 固定: false,selected:true,status:complete,title:Example Domain,url:http://www.example.com/,width:1282,windowId :10}






注意:此信息基于在我自己的测试。我没有发现Google提供的具有这种特异性的文档。在未来的Chrome版本中,确切的实际工作时间可能会发生变化。


I have a background script that periodically reloads the current tab.

var code = 'window.location.reload();';
chrome.tabs.executeScript(my_active_tab, {code: code});

After each page reload, immediately I want to inject another script.

chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab){
    if (changeInfo.status == 'complete') {
        chrome.tabs.executeScript(tabId, { file: "my_script.js" });
    }
});

Above is the code I have at the moment. The thing is, it works but it is too slow, because it literally waits after every single image has been loaded.

My goal is to execute the script immediately after DOM load. Any ideas?

解决方案

Use a manifest.json content_scripts entry with "run_at": "document_start"

Using a manifest.json content_scripts entry with "run_at": "document_start" is the only way that you can guarantee your content script is injected prior to the page existing. Code injected at this time will find both document.body and document.head will be null.

Earliest possible time to inject using tabs.executeScript()

The earliest time that works to call tabs.executeScript() is in the webRequest.onHeadersReceived event that fires after the webNavigation.onBeforeNavigate event for the page navigation you are interested in. Using tabs.executeScript() prior to this event may result in your script not being injected in the new page without any reported error. Given the inherent asynchronous nature of the timing between your background script and the process of loading the page, such failures can be intermittent, and will be affected by both OS/system configuration and the exact page that's being loaded. In fact, my statement that webRequest.onHeadersReceived will work is based on testing, as opposed to verifying in the Chrome source code. As a result, there may be corner cases which I did not test.

Injecting at that point consistently works, but the time at which the injection occurs with respect to page loading is somewhat inconsistent. Sometimes, the document.head and document.body will be null (as will always be the case with a manifest.json content_scripts injection with "run_at":"document_start"). Other times, the document.head and document.body will contain a valid DOM. It does not appear to be possible to get this timed any tighter (i.e. always have document.head and document.body be null) due to the background script and the content being in different processes: thus, inherently asynchronous.

Using webNavigation.onBeforeNavigate and not waiting for at least the associated webRequest.onHeadersReceived event is too early and does not function (content script not injected). In other words, even the associated webRequest.onSendHeaders event is too early.

Obviously, to get the content script injected that early, you have to specify runAt:'document_start' in your call to tabs.executeScript().

To inject just after the DOM exists: webNavigation.onCommitted

If you want something that is easier, and will result in the content script being injected prior to anything in the page other than the main HTML document, then you can just use the webNavigation.onCommitted event for the desired URL to trigger your tabs.executeScript(). This will result in the injected content script being loaded immediately after the main HTML document. Using webNavigation.onCommitted is made easier because it has the ability to specify a filter for your event. Thus, you can have your event listener only be called for the URLs you are interested in.

The webNavigation.onCommitted event fires after the webRequest.ResponseStarted event for the main HTML page, but before any resources are fetched (i.e. prior to any webRequest.BeforeRequest events for page resources). Interestingly, it does fire after the tabs.onUpdated event that declares a status:'loading'. The tabs.onUpdated event with status:'loading' is not a good one to trigger on by itself, because it can fire for other reasons with identical properties, but which don't indicate a page load/reload.

If you only want to tabs.executeScript() upon a page reload

The webNavigation.onCommitted event listener receives a property: transitionType, which will be different values based on the cause of the navigation. One of those values is 'reload', which you could use to filter for only page reloads.

Given that you are interested in page reload, and not loading frames, you will want to make sure that the webNavigation events are for frameId:0.

These are the events which occur when you reload a tab by clicking on the "reload this page" button:

webNavigation.onBeforeNavigate    ->  arg[0]= {"frameId":0,"parentFrameId":-1,"processId":-1,"tabId":411,"timeStamp":1500401223978.314,"url":"http://www.example.com/"}        
webRequest.onBeforeRequest        ->  arg[0]= {"frameId":0,"method":"GET","parentFrameId":-1,"requestId":"260870","tabId":411,"timeStamp":1500401223979.044,"type":"main_frame","url":"http://www.example.com/"}        
webRequest.onBeforeSendHeaders    ->  arg[0]= {"frameId":0,"method":"GET","parentFrameId":-1,"requestHeaders":[{"name":"Upgrade-Insecure-Requests","value":"1"},{"name":"User-Agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"},{"name":"Accept","value":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"},{"name":"Accept-Encoding","value":"gzip, deflate"},{"name":"Accept-Language","value":"en-US,en;q=0.8"}],"requestId":"260870","tabId":411,"timeStamp":1500401223979.3242,"type":"main_frame","url":"http://www.example.com/"}        
webRequest.onSendHeaders          ->  arg[0]= {"frameId":0,"method":"GET","parentFrameId":-1,"requestHeaders":[{"name":"Upgrade-Insecure-Requests","value":"1"},{"name":"User-Agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"},{"name":"Accept","value":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"},{"name":"Accept-Encoding","value":"gzip, deflate"},{"name":"Accept-Language","value":"en-US,en;q=0.8"}],"requestId":"260870","tabId":411,"timeStamp":1500401223979.538,"type":"main_frame","url":"http://www.example.com/"}        
webRequest.onHeadersReceived      ->  arg[0]= {"frameId":0,"method":"GET","parentFrameId":-1,"requestId":"260870","responseHeaders":[{"name":"Content-Encoding","value":"gzip"},{"name":"Accept-Ranges","value":"bytes"},{"name":"Cache-Control","value":"max-age=604800"},{"name":"Content-Type","value":"text/html"},{"name":"Date","value":"Tue, 18 Jul 2017 18:07:03 GMT"},{"name":"Etag","value":"\"359670651\""},{"name":"Expires","value":"Tue, 25 Jul 2017 18:07:03 GMT"},{"name":"Last-Modified","value":"Fri, 09 Aug 2013 23:54:35 GMT"},{"name":"Server","value":"ECS (rhv/818F)"},{"name":"Vary","value":"Accept-Encoding"},{"name":"X-Cache","value":"HIT"},{"name":"Content-Length","value":"606"}],"statusCode":200,"statusLine":"HTTP/1.1 200 OK","tabId":411,"timeStamp":1500401224072.296,"type":"main_frame","url":"http://www.example.com/"}        
---^^^^^^^^^^^^^^^^^^^^^^^^^-Earliest tabs.executeScript() injection is in the handler for the webRequest.onHeadersReceived event.
webRequest.onResponseStarted      ->  arg[0]= {"frameId":0,"fromCache":false,"ip":"93.184.216.34","method":"GET","parentFrameId":-1,"requestId":"260870","responseHeaders":[{"name":"Content-Encoding","value":"gzip"},{"name":"Accept-Ranges","value":"bytes"},{"name":"Cache-Control","value":"max-age=604800"},{"name":"Content-Type","value":"text/html"},{"name":"Date","value":"Tue, 18 Jul 2017 18:07:03 GMT"},{"name":"Etag","value":"\"359670651\""},{"name":"Expires","value":"Tue, 25 Jul 2017 18:07:03 GMT"},{"name":"Last-Modified","value":"Fri, 09 Aug 2013 23:54:35 GMT"},{"name":"Server","value":"ECS (rhv/818F)"},{"name":"Vary","value":"Accept-Encoding"},{"name":"X-Cache","value":"HIT"},{"name":"Content-Length","value":"606"}],"statusCode":200,"statusLine":"HTTP/1.1 200 OK","tabId":411,"timeStamp":1500401224072.5032,"type":"main_frame","url":"http://www.example.com/"}        
webRequest.onCompleted            ->  arg[0]= {"frameId":0,"fromCache":false,"ip":"93.184.216.34","method":"GET","parentFrameId":-1,"requestId":"260870","responseHeaders":[{"name":"Content-Encoding","value":"gzip"},{"name":"Accept-Ranges","value":"bytes"},{"name":"Cache-Control","value":"max-age=604800"},{"name":"Content-Type","value":"text/html"},{"name":"Date","value":"Tue, 18 Jul 2017 18:07:03 GMT"},{"name":"Etag","value":"\"359670651\""},{"name":"Expires","value":"Tue, 25 Jul 2017 18:07:03 GMT"},{"name":"Last-Modified","value":"Fri, 09 Aug 2013 23:54:35 GMT"},{"name":"Server","value":"ECS (rhv/818F)"},{"name":"Vary","value":"Accept-Encoding"},{"name":"X-Cache","value":"HIT"},{"name":"Content-Length","value":"606"}],"statusCode":200,"statusLine":"HTTP/1.1 200 OK","tabId":411,"timeStamp":1500401224074.0261,"type":"main_frame","url":"http://www.example.com/"}        
tabs.onUpdated                    ->  arg[0]= 411 :: arg[1]= {"status":"loading","url":"http://www.example.com/"} :: arg[2]= {"active":true,"audible":false,"autoDiscardable":true,"discarded":false,"height":902,"highlighted":true,"id":411,"incognito":false,"index":1,"mutedInfo":{"muted":false},"pinned":false,"selected":true,"status":"loading","title":"www.example.com","url":"http://www.example.com/","width":1282,"windowId":10}    
tabs.onZoomChange                 ->  arg[0]= {"newZoomFactor":1,"oldZoomFactor":1,"tabId":411,"zoomSettings":{"mode":"automatic","scope":"per-origin"}}        
webNavigation.onCommitted         ->  arg[0]= {"frameId":0,"processId":107,"tabId":411,"timeStamp":1500401224079.4019,"transitionQualifiers":[],"transitionType":"reload","url":"http://www.example.com/"}
--->>Here is where you can tell it's a reload --------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^
history.onVisited                 ->  arg[0]= {"id":"42","lastVisitTime":1500401224077.579,"title":"Example Domain","typedCount":1,"url":"http://www.example.com/","visitCount":12}        
tabs.onUpdated                    ->  arg[0]= 411 :: arg[1]= {"title":"Example Domain"} :: arg[2]= {"active":true,"audible":false,"autoDiscardable":true,"discarded":false,"height":902,"highlighted":true,"id":411,"incognito":false,"index":1,"mutedInfo":{"muted":false},"pinned":false,"selected":true,"status":"loading","title":"Example Domain","url":"http://www.example.com/","width":1282,"windowId":10}    
webNavigation.onDOMContentLoaded  ->  arg[0]= {"frameId":0,"processId":107,"tabId":411,"timeStamp":1500401224093.404,"url":"http://www.example.com/"}        
webNavigation.onCompleted         ->  arg[0]= {"frameId":0,"processId":107,"tabId":411,"timeStamp":1500401224094.768,"url":"http://www.example.com/"}        
tabs.onUpdated                    ->  arg[0]= 411 :: arg[1]= {"status":"complete"} :: arg[2]= {"active":true,"audible":false,"autoDiscardable":true,"discarded":false,"height":902,"highlighted":true,"id":411,"incognito":false,"index":1,"mutedInfo":{"muted":false},"pinned":false,"selected":true,"status":"complete","title":"Example Domain","url":"http://www.example.com/","width":1282,"windowId":10}   


Note: This information is based on my own testing. I have found no documentation from Google with this level of specificity. The exact timing of what actually works may change in future versions of Chrome.

这篇关于谷歌Chrome扩展:如何在页面重新加载后立即注入脚本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆