背景介绍

因为正在开发一个项目,而这个项目使用到了puppeteer,其中有个功能是在puppeteer打开的chrome里打开多个Tab,并进行管理。 虽然puppeteer可以打开多个网站,但是并不利于管理,所有我使用的是插件的方式,通过插件来打开多网站,并进行管理。

但是这里有个需求是,当网站崩溃时,我要做出一些操作。但是目前网上没有一个好的办法去监听当前网站是否崩溃。

可能有同学会说:puppeteer不是提供了一个page.on('error', fn)的方法,来进行监听么?

请注意上文中提到的,使用插件打开多个网站,puppeteer提供的方法只能对自己打开的网站起作用,没有使用puppeteer打开的网站,page.on('error', fn)方法无能为力。

使用Service Workers

这个方法是由我同事Haitao提出来的思路。

在当前网站上运行一个Service Workers,因为在运行的时候Service Workers会再启动一个单独的进程,当前网站和Service Workers是两个单独的进程。也就是说当网站崩溃时,并不影响Service Workers进程。所以可通过心跳检测来进行判断网站是否崩溃。

网上也有阿里的同学写的相关文章:如何监控网页崩溃?

但是我并没有使用这个方式,因为当Service Workers崩溃了,那就没有任何办法了,可能有同学会说:网站和Service Workers互相发心跳检测。这可能是一种办法,但是我不太喜欢这种方式。

使用Webkit的远程调试协议

介绍

在开始前,我们先去看下puppeteer的源码,为什么puppeteer可以监听到网页的崩溃。

其代码在lib/Page.js文件里。

首先可以看到Page是一个Class,其继承了EventEmitterEventEmitterpage提供了on方法,也就是我们之前看到的:page.on('error', fn)

从这里就可知,在Page Class里,有地方调用了this.emit('error')来触发error event。搜了一下,发现其代码在_onTargetCrashed方法里。如:

触发crash的方法,我们找到了。那这个_onTargetCrashed又是在哪触发的呢?

可见,是一个叫client的方法监听到了Inspector.targetCrashed事件,而这个事件触发了_onTargetCrashed函数,clinet方法就不再跟了,因为跳地方较多,只需要知道,最终client是一个websocket的产物。而websocket创建的代码在lib/Launcher.js里。代码位置

注意这两行:

const transport = new PipeTransport((chromeProcess.stdio[3]), (chromeProcess.stdio[4]));connection = new Connection('', transport, slowMo);

chromeProcessnodejs中的spawn产物,代码为:

代码位置

const chromeProcess = childProcess.spawn(chromeExecutable,chromeArguments,{detached: process.platform !== 'win32',env,stdio}
);

其中chromeArgumentschrome启动的参数列表,此列表是有一个--remote-debugging-的:

代码位置

if (!chromeArguments.some(argument => argument.startsWith('--remote-debugging-')))chromeArguments.push(pipe ? '--remote-debugging-pipe' : '--remote-debugging-port=0');

现在就明朗多了,Inspector.targetCrashed这个事件,是由Webkit远程调试协议也就是remote debugging protocol提供的。

其定义在webkit的Inspector.json里: Source/WebCore/inspector/Inspector.json#L39-L42

关于这个event的commit url为:github.com/WebKit/webk…

编写解决方案代码

现在我们知道了,只要能监听到Inspector.targetCrashed事件,就可以知道网站是否关闭了。我们先在puppeteer的启动参数里,增加一行启动参数:

puppeteer.launch({'--remote-debugging-port=9222',// other args
});

puppeteer启动时,会监听本地的9222端口,其中路径/json为当前的详情。如:

其格式为:

[{"description": "","devtoolsFrontendUrl": "/devtools/inspector.html?ws=127.0.0.1:9222/devtools/page/A1CB5A9CC25A7EE8A99C6A4A1876E4D3","faviconUrl": "https://s.ytimg.com/yts/img/favicon_32-vflOogEID.png","id": "A1CB5A9CC25A7EE8A99C6A4A1876E4D3","title": "張三李四 Chang and Lee 【等無此人 Waiting】 - YouTube","type": "page","url": "https://www.youtube.com/watch?v=lAcUGvpRkig&list=PL3p0C_7POnMHG-b0dzkeTVdNuM6yRE5iQ&index=10&t=0s","webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/A1CB5A9CC25A7EE8A99C6A4A1876E4D3"},// other
{

其中的type为当前进程的详情:

  • page: 网页
  • iframe: 网页嵌套的iframe
  • background_page: 插件页面
  • service_worker: Service Workers

这个type的作用在于,你只想监听某一类型的崩溃。

还有一个更主要的字段:webSocketDebuggerUrl。我们将使用这个字段的值,来进行获取消息。有一个简单的demo:

const http =  require('http');
const WebSocket = require('ws');http.get('http://127.0.0.1:9222/json', res => {res.addListener('data', data => {const result = JSON.parse(data.toString());result.forEach(info => {const client = new WebSocket(info.webSocketDebuggerUrl);client.on('message', data => {if (data.indexOf('"method":"Inspector.targetCrashed"') !== -1) {console.error('crash!');}});});})
})

先看懂这段代码,后面的代码才好理解,因为代码过于简单,这里就不再介绍了。

这段代码有个问题是,插件打开网站时,会存在一定的延迟,可能会导致某些网站没有被监听到,而且当这段代码运行后,插件再打开网站时,也不会监听到。针对这个问题,优化了下代码:

const http =  require('http');
const WebSocket = require('ws');module.exports = () => {const wsList = {};let crashStaus = false;const getWsList = () => {return new Promise((resolve) => {http.get('http://127.0.0.1:9222/json', res => {res.addListener('data', data => {try {const result = JSON.parse(data.toString());const tempWsList = {};result.forEach(info => {if (typeof wsList[info.id] === 'undefined') {tempWsList[info.id] = info.webSocketDebuggerUrl;wsList[info.id] = info.webSocketDebuggerUrl;}});if (Object.keys(tempWsList).length !== 0) {resolve(tempWsList);}} catch (e) {console.error(e);}});});});};setInterval(() => {getWsList().then(list => {Object.values(list).forEach(wsUrl => {const client = new WebSocket(wsUrl);client.on('message', data => {if (data.indexOf('"method":"Inspector.targetCrashed"') !== -1) {if (!crashStaus) {crashStaus = true;console.log('crash!!!');}}});})});}, 1000);
};

其中需要说明一下这段代码:

if (!crashStaus) {crashStaus = true;console.log('crash!!!');
}

因为我的需求是,任何一个进程crash了,就关闭整个服务,重新运行。所以如果有多个进程同时crash了。我的代码只走一次,不想让他走多次。这个是针对我这里的需求,各位同学可以根据自己的需求更改代码。

参考

Webkit 远程调试协议初探

Chrome 远程调试协议分析与实战

作者信息

  • Author: Black-Hole
  • Blog: bugs.cc/
  • Github: github.com/BlackHole1/
  • Twitter: twitter.com/Free_BlackH…
  • Email: 158blackhole@gmail.com

其他

我司(爱乐奇)招人,感兴趣的小伙伴可以来投简历呀。

弹性工作制、每日水果、同事都特别nice、965、团建、五险一金...

地点上海浦软大厦

转载于:https://juejin.im/post/5cbd747d5188250a98584917

通过Webkit远程调试协议监听网页崩溃相关推荐

  1. Chrome 远程调试协议分析与实战

    背景 某一天,A 君想获取 Chrome 页面中的性能数据,诸如时间.白屏和首屏等,因为需要和竞品进行对比分析,无法注入代码,该怎么办? 此时,你也许能想到开发者工具(DevTools),也许知道Ti ...

  2. 博客系统。集成调试平台,支持类结构/jar结构预览、支持方法调试和监听、支持修改类字段(变量、常量、枚举)等

    介绍: 1.博主博客:http://54sb.org 2.demo站:http://test.coody.org/ 3.demo站后台:http://test.coody.org/admin 用户名: ...

  3. 【计算机网络】数据链路层 : CSMA 协议 ( 载波监听多路访问协议 | 监听 | 1-坚持 CSMA | 非坚持 CSMA | p-坚持 CSMA )

    文章目录 一. CSMA 协议 ( 载波监听多路访问协议 ) 二. CSMA 协议 监听 三. 1-坚持 CSMA 四. 非坚持 CSMA 五. p-坚持 CSMA 六. 三种协议对比 一. CSMA ...

  4. chrome扩展(插件)开发(五)监听网页的ajax请求

    我的插件想要监听网页发出的请求, 然后根据请求的状态来做具体的操作. 实现的方法主要有三种方式 google官方提供的api chrome.webRequest 这里在插件中监听宿主页面的ajax 重 ...

  5. PC端chrome浏览器如何调试多点触控事件/chrome浏览器远程调试手机上的网页

    PC端chrome浏览器如何调试多点触控事件/chrome浏览器远程调试手机上的网页 最近学习移动端网页开发的时候,遇到了一个问题,如何在真机上看到控制台输出的内容. 虽然现在的桌面浏览器提供了模拟手 ...

  6. electron监听网页_Electron 进程通信

    本文作者:IMWeb laynechen 未经同意,禁止转载 Electron 中的进程分类 在 Electron 中,存在两种进程:主进程和渲染进程. 主进程 (Main Process) 一个 E ...

  7. WebView监听网页加载成功与失败

    问题说明: 现在好多APP在应用中会内嵌webview,好多时候需要监听webview是否加载成功与失败.当加载成功的时候会回调WebViewClient的onPageFinished方法:当加载失败 ...

  8. php监听网页日志,如何用php程序监听一个不断增长的日志文件

    首先这个日志文件写入不是很频繁,它每一行就是一条有效的日志.我想php程序来监听这个文件,每当被写入一行的时候,我的php就自动读入一行,做出分析然后做相应的处理.请问要如何实现呢? 回复内容: 首先 ...

  9. 利用FireFox远程调试安卓手机web网页应用

    1.问题 解决在手机浏览器中访问自己所开发开发的web应用时怎么进行调试和查看控制台信息 2.准备 手机安装FireFox浏览器,并打开火狐浏览器中的usb远程调试模式 手机上打开手机系统为usb调试 ...

最新文章

  1. 销售流程管理-leangoo
  2. 值得收藏的45个Python优质资源(附链接)
  3. Vite与webpack优势
  4. vantUI组件:van-card 自定义内容 - 踩坑篇
  5. Python学习-储存器
  6. C言语次序查找算法及代码
  7. C/C++[结构体]
  8. 【预测模型】基于贝叶斯优化的LSTM模型实现数据预测matlab源码
  9. PatterNodes for Mac(创建图形模式)
  10. 四阶巴特沃斯低通滤波器设计
  11. twaver html5 2d demo,TWaver 2D+GIS+3D的试用和在线Demo
  12. 厦门大学计算机科学与工程学院,厦门大学
  13. 【NOIP2014】生活大爆炸版石头剪刀布
  14. linux下打开.mpp文件(微软project).
  15. Hadoop-HDFS详解与HA,完全分布式集群搭建(细到令人发指的教程)
  16. 1.GraphPad Prism 8软件安装
  17. 14个种类,600款笔刷!如何做一套属于自己的精美笔刷?
  18. 【报告分享】2020中国教育培训移动应用发展研究报告-TalkingData(附下载)
  19. abp+dapper+mysql_abp集成abp.Dapper
  20. NVIDIA Jetson NX配置深度学习环境(Pytorch、torchvision)超级详细,torchvision安装避坑总结

热门文章

  1. 实时热点网站有哪些?3个超实用的热点网站,轻松找热点
  2. 一个程序员的自由职业者生涯
  3. 成都盛铭轩:店铺数据分析方法
  4. 优启通U盘安装原版Win xp系统教程
  5. linux删除卷组命令,介绍如何从LVM的卷组中删除物理卷
  6. rofl文件如何播放
  7. 贵州省网上办事大厅办事流程
  8. 学习SCI论文绘制技巧(A)
  9. Beautiful Soup简单使用
  10. uniapp小程序更改swiper指示点样式