黄聪:如何扩展Chrome DevTools来获取页面请求

1. Chrome DevTools Extension

熟悉React的同窗,可能对React Developer Tools并不陌生,
javascript

 
 

 

刚看到的时候,我也以为很神奇,
由于React Developer Tools和其余Chrome Extension不一样,
它竟然出如今了Chrome开发者工具栏中,和原生的DevTools同样强大。
例如,能够审查元素,查看元素的属性,等等。css

后来才知道,像这种出如今Chrome开发者工具栏中的扩展,称为Chrome DevTools Extensionhtml

比起普通的Chrome Extension,Chrome DevTools Extension能够访问更多API,例如,
(1)devtools.inspectedWindow
(2)devtools.network
(3)devtools.panels
其中包括了,与当前审查窗口相关的,与网络请求相关的,以及与开发者工具栏相关的API。java

2. 背景 & 基本概念

 
 

在某一具体项目中,有一个这样的需求,
咱们须要选择页面中发起的http请求,而后将它们保存到数据库中。react

因为页面发起的请求可能会发往不一样的服务器,因此在服务器端解决这个问题就显得比较麻烦,
而编写一个Chrome DevTools Extension会更简单直接。git

下文我将这个功能的核心抽离出来,做为一个例子,来还原Chrome DevTools Extension的编写方法。
为此,咱们先熟悉几个基本的概念。github

(1)tab页

Chrome浏览器是由tab页组成的,一个浏览器实例中能够打开多个tab页。web


 
 

(2)DevTools Window

每一个tab页,均可以打开本身的开发者工具窗口,称为DevTools Window。chrome


 
 

注意,每一个tab页都有本身独立的DevTools Window,
只是切换tab页的时候,只会显示当前tab页的DevTools Window。数据库

(3)DevTools Page 和 Panel

下面咱们来建立一个Chrome DevTools Extension项目,目录结构以下,

chrome-devtools-extension-example
├── devtools.html    // DevTool Page ├── devtools.js // DevTool Page中引用的js ├── manifest.json // 入口 ├── panel.html // 开发者工具栏选项卡页面 └── panel.js // 选项卡页面中引用的js 

其中manifest.json是入口,它会声明一个对用户不可见的DevTools Page。
在本例中为devtools.html

{
  "name": "PageRecorder", "version": "1.1.0", "minimum_chrome_version": "10.0", "description": "Record all http requests in a page.", "devtools_page": "devtools.html", "manifest_version": 2 } 

DevTools Page引入的js,具备访问DevTools API的能力,
包括上文提到的那些API,devtools.inspectedWindowdevtools.networkdevtools.panels

DevTools Page对用户是不可见的,若是须要在开发者工具栏中建立新的DevTool选项卡,
还须要在DevTools Page使用一下方法来建立,DevTool选项卡,官方称为Panel。
原生的Panel包括,Elements,Console,Network,等等。

// 建立一个Panel chrome.devtools.panels.create( // title 'ChromeDevToolsExtensionExample', // iconPath null, // pagePath 'panel.html' ); 

以上,咱们在DevTool Page中建立了一个新的Panel,名字为ChromeDevToolsExtensionExample

 
 

 

其中,panel.html,咱们只是简单的写了一个Hello World!
值得注意的是,每一个Panel均可以加载本身的html,js和css,且具备和DevTools Page同样的权限。

(4)Panel的生命周期

Panel只有在第一次被激活的时候,才进行实例化,
同一个DevTools Window中的不一样Panel切换时,不会从新加载。
当前tab页刷新时,Panel也不会从新加载。

DevTools Window关闭后,Panel将被销毁。

所以,咱们要想使用Chrome DevTools Extension,就必须先打开开发者工具窗口,
而后再激活咱们新建的DevTools Panel。

3. 监听请求

 
 

上文咱们提到了,Chrome DevTools Extension能够访问devtools.network API,
如今咱们来展现使用chrome.devtools.network.onRequestFinished.addListener来获取请求。
为此,咱们新建了一个panel.js文件,并在panel.html中引用它。

// Chrome DevTools Extension中不能使用console.log const log = (...args) => chrome.devtools.inspectedWindow.eval(` console.log(...${JSON.stringify(args)}); `); // 注册回调,每个http请求响应后,都触发该回调 chrome.devtools.network.onRequestFinished.addListener(async (...args) => { try { const [{ // 请求的类型,查询参数,以及url request: { method, queryString, url }, // 该方法可用于获取响应体 getContent, }] = args; log(method, queryString, url); // 将callback转为await promise // warn: content在getContent回调函数中,而不是getContent的返回值 const content = await new Promise((res, rej) => getContent(res)); log(content); } catch (err) { log(err.stack || err.toString()); } }); 

以上就是panel.js的完整内容了,咱们还须要作如下几点说明,

 
 

 

(1)Chrome DevTools Extension中,不能直接使用console.log
因此本例中使用了devtools.inspectedWindow API中的chrome.devtools.inspectedWindow.eval方法,
在当前审查的窗口中直接求值一段js代码,从而间接实现打印日志的功能。

(2)与获取http请求的methodqueryStringurl不一样的是,
咱们须要调用getContent方法来获取http响应体,
而且,getContent是一个高阶的异步函数

所谓高阶函数,指的是,它接受一个回调函数做为参数getContent(content=>{ })
这个回调函数的参数content,才是对应http请求的响应体。

所谓异步,指的是,当回调函数还没触发的时候,getContent就已经返回了。
这也致使了事件监听函数,也不得不具备异步性。

(3)因为事件监听函数是异步的,
因此,有可能在上一个onRequestFinished事件还未处理完的状况下,
下一个onRequestFinished的监听函数就又被触发了。

这就致使了,以上例子中,log(method, queryString, url);log(content);
多是乱序打印的。

这个问题咱们曾经讨论过,可参考:怎样按触发顺序执行异步任务

总结

到此为止,咱们最简版的Chrome DevTools Extension示例已经介绍完了,
如下是能够运行的源码地址:github: chrome-extension-example
(注:不是master分支,而是simply分支。

Chrome扩展遵循一种优秀的设计原则,
那就是在设计系统的时候,应该想办法让扩展对用户而言,与原生功能平权。 这种对称性,会拉近原生与扩展之间的距离,从而让系统架构从一开始就创建在灵活的基础之上。

做者:何幻 连接:https://www.jianshu.com/p/4ce7f58b8c84 來源:简书 简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。
相关文章
相关标签/搜索