网站监控网页内容监测(本文是如何监控网页的崩溃上的?(图))
优采云 发布时间: 2021-11-25 13:02网站监控网页内容监测(本文是如何监控网页的崩溃上的?(图))
这篇文章如何监控网页的卡顿?下一部分。今天我们的主题是如何监控网页崩溃。
崩溃和冻结有什么区别?
Stallion 是指网页暂时响应缓慢,可能无法及时执行 JS。这也是上一篇网页卡顿监控所依赖的技术点。
但崩溃是不同的。网页全部崩溃,页面不再可见,JS不再运行。有没有办法监控网页的崩溃并报告?
然而,天上总有一条路。
load 和 beforeunload 事件
上网查了一下,几乎找不到办法,终于遇到了这个文章。本文使用window对象的load和beforeunload事件来监控网页崩溃。
window.addEventListener('load', function () {
sessionStorage.setItem('good_exit', 'pending');
setInterval(function () {
sessionStorage.setItem('time_before_crash', new Date().toString());
}, 1000);
});
window.addEventListener('beforeunload', function () {
sessionStorage.setItem('good_exit', 'true');
});
if(sessionStorage.getItem('good_exit') &&
sessionStorage.getItem('good_exit') !== 'true') {
/*
insert crash logging code here
*/
alert('Hey, welcome back from your crash, looks like you crashed on: ' + sessionStorage.getItem('time_before_crash'));
}
一张图片胜过千言万语:
使用 load 和 beforeunload 事件实现崩溃监控
该解决方案巧妙地利用了页面崩溃无法触发 beforeunload 事件的事实。
当页面加载(加载事件)时,在 sessionStorage 中记录 good_exit 状态为pending。如果用户正常退出(beforeunload 事件),状态变为true。如果它崩溃,状态保持挂起。当用户第二次访问网页时(第二个A加载事件),查看good_exit的状态,如果还是pending,可以断定上次访问网页崩溃了!
但是这个方案有问题:
使用 sessionStorage 来存储状态,但通常在网页崩溃或死机后,用户会强行关闭网页或干脆重新打开浏览器,sessionStorage 会存储状态,但状态将不再存在;如果状态存储在localStorage甚至Cookie中,如果用户打开多个A网页,但没有关闭,good_exit存储总是pending。之后,每次打开网页都会报crash。这种方案在全国广播公司成立之初就采用了。发现即使页面优化了,crash也没有减少,和PV保持比例,才实现了这个解决方案的问题。基于Service Worker的崩溃统计解决方案
随着 PWA 概念的普及,大家也逐渐熟悉了 Service Worker。由于以下原因,我们可以使用 Service Worker 来监控网页崩溃:
Service Worker 有自己独立的工作线程,与网页分离。如果网页崩溃,Service Worker 在正常情况下不会崩溃。Service Worker 的生命周期一般比网页的生命周期长,可以用来监控网页的状态。navigator.serviceWorker.controller.postMessage API 向负责的 SW 发送消息。
基于以上几点,我们可以实现一个基于心跳检测的监控方案:
一些简化的检测代码供您参考:
// 页面 JavaScript 代码
if (navigator.serviceWorker.controller !== null) {
let HEARTBEAT_INTERVAL = 5 * 1000; // 每五秒发一次心跳
let sessionId = uuid();
let heartbeat = function () {
navigator.serviceWorker.controller.postMessage({
type: 'heartbeat',
id: sessionId,
data: {} // 附加信息,如果页面 crash,上报的附加数据
});
}
window.addEventListener("beforeunload", function() {
navigator.serviceWorker.controller.postMessage({
type: 'unload',
id: sessionId
});
});
setInterval(heartbeat, HEARTBEAT_INTERVAL);
heartbeat();
}
const CHECK_CRASH_INTERVAL = 10 * 1000; // 每 10s 检查一次
const CRASH_THRESHOLD = 15 * 1000; // 15s 超过15s没有心跳则认为已经 crash
const pages = {}
let timer
function checkCrash() {
const now = Date.now()
for (var id in pages) {
let page = pages[id]
if ((now - page.t) > CRASH_THRESHOLD) {
// 上报 crash
delete pages[id]
}
}
if (Object.keys(pages).length == 0) {
clearInterval(timer)
timer = null
}
}
worker.addEventListener('message', (e) => {
const data = e.data;
if (data.type === 'heartbeat') {
pages[data.id] = {
t: Date.now()
}
if (!timer) {
timer = setInterval(function () {
checkCrash()
}, CHECK_CRASH_INTERVAL)
}
} else if (data.type === 'unload') {
delete pages[data.id]
}
})
代码很简单,我就不细说了。
方案的可行性
兼容性:
Service Worker 的渗透率已经相当高了。鉴于国内的各种浏览器都是Chrome内核,而且版本已经在Chrome 45以上,已经覆盖了相当多的用户。作为监控,大部分数据覆盖都不错。
Service Worker 兼容性
可靠性:
这应该是我知道的可以比较准确的判断网页崩溃的方式。不过,我们的方案还在测试环境中,上线一段时间后会和大家分享数据。
对浏览器供应商的建议
在 Chrome 中访问 chrome://crashes/ 可以看到标题图片的崩溃列表。如果厂商能提供一个API,在页面打开的时候能知道用户上次崩溃的信息就好了!