web前端监控的三个方面探讨
一. js错误监控方式
1. 主动判断
我们在一些运算之后,得到一个期望的结果,然而结果不是我们想要的
// test.js
function calc(){
// code...
return val;
}
if(calc() !== "someVal"){
Reporter.send({
position: "test.js::<Function>calc"
msg: "calc error"
});
}
这种属于逻辑错误/状态错误的反馈,在接口 status
判断中用的比较多。
2. try..catch
捕获
判断一个代码段中存在的错误:
try {
init();
// code...
} catch(e){
Reporter.send(format(e));
}
以 init
为程序的入口,代码中所有同步执行出现的错误都会被捕获,这种方式也可以很好的避免程序刚跑起来就挂。
3. window.onerror
捕获全局错误:
window.onerror = function() {
var errInfo = format(arguments);
Reporter.send(errInfo);
return true;
};
在上面的函数中返回 return true
,错误便不会暴露到控制台中。下面是它的参数信息:
/**
* @param {String} errorMessage 错误信息
* @param {String} scriptURI 出错的文件
* @param {Long} lineNumber 出错代码的行号
* @param {Long} columnNumber 出错代码的列号
* @param {Object} errorObj 错误的详细信息,Anything
*/
window.onerror = function(errorMessage, scriptURI, lineNumber,columnNumber,errorObj) {
// code..
}
window.onerror
算是一种特别暴力的容错手段,try..catch
也是如此,他们底层的实现就是利用 C/C++ 中的 goto
语句实现,一旦发现错误,不管目前的堆栈有多深,不管代码运行到了何处,直接跑到顶层或者 try..catch
捕获的那一层,这种一脚踢开错误的处理方式并不是很好。
关于 window.onerror 还有两点需要值得注意
- 对于 onerror 这种全局捕获,最好写在所有 JS 脚本的前面,因为你无法保证你写的代码是否出错,如果写在后面,一旦发生错误的话是不会被 onerror 捕获到的。
- 另外 onerror 是无法捕获到网络异常的错误。
当我们遇到 <img src="./404.png">
报 404 网络请求异常的时候,onerror 是无法帮助我们捕获到异常的。
<script>
window.onerror = function (msg, url, row, col, error) {
console.log('我知道异步错误了');
console.log({
msg, url, row, col, error
})
return true;
};
</script>
<img src="./404.png">
由于网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行,但是这种方式虽然可以捕捉到网络请求的异常,但是无法判断 HTTP 的状态是 404 还是其他比如 500 等等,所以还需要配合服务端日志才进行排查分析才可以。
<script>
window.addEventListener('error', (msg, url, row, col, error) => {
console.log('我知道 404 错误了');
console.log(
msg, url, row, col, error
);
return true;
}, true);
</script>
<img src="./404.png" alt="">
这点知识还是需要知道,要不然用户访问网站,图片 CDN 无法服务,图片加载不出来而开发人员没有察觉就尴尬了。
Promise 错误
通过 Promise 可以帮助我们解决异步回调地狱的问题,但是一旦 Promise 实例抛出异常而你没有用 catch 去捕获的话,onerror 或 try-catch 也无能为力,无法捕捉到错误。
window.addEventListener('error', (msg, url, row, col, error) => {
console.log('我感知不到 promise 错误');
console.log(
msg, url, row, col, error
);
}, true);
Promise.reject('promise error');
new Promise((resolve, reject) => {
reject('promise error');
});
new Promise((resolve) => {
resolve();
}).then(() => {
throw 'promise error'
});
虽然在写 Promise 实例的时候养成最后写上 catch 函数是个好习惯,但是代码写多了就容易糊涂,忘记写 catch。
所以如果你的应用用到很多的 Promise 实例的话,特别是你在一些基于 promise 的异步库比如 axios 等一定要小心,因为你不知道什么时候这些异步请求会抛出异常而你并没有处理它,所以你最好添加一个 Promise 全局异常捕获事件 unhandledrejection。
window.addEventListener("unhandledrejection", function(e){
e.preventDefault()
console.log('我知道 promise 的错误了');
console.log(e.reason);
return true;
});
Promise.reject('promise error');
new Promise((resolve, reject) => {
reject('promise error');
});
new Promise((resolve) => {
resolve();
}).then(() => {
throw 'promise error'
});
window.onerror 能否捕获 iframe 的错误
当你的页面有使用 iframe 的时候,你需要对你引入的 iframe 做异常监控的处理,否则一旦你引入的 iframe 页面出现了问题,你的主站显示不出来,而你却浑然不知。
首先需要强调,父窗口直接使用 window.onerror 是无法直接捕获,如果你想要捕获 iframe 的异常的话,有分好几种情况。
如果你的 iframe 页面和你的主站是同域名的话,直接给 iframe 添加 onerror 事件即可。
<iframe src="./iframe.html" frameborder="0"></iframe>
<script>
window.frames[0].onerror = function (msg, url, row, col, error) {
console.log('我知道 iframe 的错误了,也知道错误信息');
console.log({
msg, url, row, col, error
})
return true;
};
</script>
读者可以通过 npm run iframe
查看效果:
如果你嵌入的 iframe 页面和你的主站不是同个域名的,但是 iframe 内容不属于第三方,是你可以控制的,那么可以通过与 iframe 通信的方式将异常信息抛给主站接收。与 iframe 通信的方式有很多,常用的如:postMessage,hash 或者 name 字段跨域等等,这里就不展开了,感兴趣的话可以看:跨域,你需要知道的全在这里
如果是非同域且网站不受自己控制的话,除了通过控制台看到详细的错误信息外,没办法捕获,这是出于安全性的考虑,你引入了一个百度首页,人家页面报出的错误凭啥让你去监控呢,这会引出很多安全性的问题。
异常上报方式
监控拿到报错信息之后,接下来就需要将捕捉到的错误信息发送到信息收集平台上,常用的发送形式主要有两种:
- 通过 Ajax 发送数据
- 动态创建 img 标签的形式
实例 - 动态创建 img 标签进行上报
function report(error) {
var reportUrl = 'http://xxxx/report';
new Image().src = reportUrl + 'error=' + error;
}
收集异常信息量太多,怎么办
如果你的网站访问量很大,假如网页的 PV 有 1kw,那么一个必然的错误发送的信息就有 1kw 条,我们可以给网站设置一个采集率:
Reporter.send = function(data) {
// 只采集 30%
if(Math.random() < 0.3) {
send(data) // 上报错误信息
}
}
二. 接口请求时长
/**
* 拦截接口请求,上报接口信息
*/
//统一拦截ajax请求
var start_time = 0,
gap_time = 0; //计算请求延时
window.addEventListener('ajaxReadyStateChange', function (e) {
var xhr = e.detail,
status = xhr.status,
readyState = xhr.readyState,
responseText = xhr.responseText; /**
* 计算请求延时
*/
if(readyState == 1){
start_time = (new Date()).getTime();
}
if(readyState == 4){
gap_time = (new Date()).getTime() - start_time;
}
/**
* 上报请求信息
* @Author smy
* @DateTime 2018-06-27T16:32:30+0800
*/
if(readyState == 4){
httpReport(gap_time, status, xhr.responseURL)
} })
三. 页面加载时长
参见:https://blog.oldj.net/2012/01/09/measuring-the-user-latency/
--------------------------------------------------------------
已知问题:
1. ios苹果不支持crossorigin=“anonymous”, 只支持crossorigin="use-credentials",cdn 不支持credentials。
2. ios 会对客户端调用webview方法找不到进行报错到window.onerror, 当上报的值是不存在的对象属性时,报错内容为global code,比如这时上报error.stack, 此时error为null,应上报message。
---------------------------------------------------------------
参考:
https://www.cnblogs.com/hustskyking/p/fe-monitor.html
http://web.jobbole.com/93684/
https://github.com/happylindz/blog/issues/5
web前端监控的三个方面探讨的更多相关文章
- web前端安全的三个关键点
一.浏览器的同源策略 同源策略:不同域的客户端脚本在未经授权的情况下不能读写对方的资源. 这里有几个关键词:域.脚本.授权.读写.资源 1.同域要求两个站点:同协议.同域名.同端口.下表展示了所列站点 ...
- web前端学习(三)css学习笔记部分(8)-- SVN的介绍和应用、CSS动画效果、CSS3布局属性全接触
15.SVN的介绍和应用 15.1.SVN的介绍和应用课程概要 将代码进行集中管理,有版本号的进行迭代,方便集体工作的build流程 15.2.SVN的介绍 SVN是Subversion的简称,是一个 ...
- Sentry Web 前端监控 - 最佳实践(官方教程)
系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Maps Sentry For ...
- web前端学习(三)css学习笔记部分(5)-- CSS动画--页面特效、HTML与CSS3简单页面效果实例
CSS动画--页面特效部分内容目前仅仅观看了解内容,记录简单笔记,之后工作了进行内容的补充 7. CSS动画--页面特效 7.1 2D.3D转换 7.1.1 通过CSS3转换,我们能够对元素进行 ...
- web前端学习(三)css学习笔记部分(7)-- 文字和字体相关样式、盒子相关样式、背景与边框相关样式
12. 文字和字体相关样式 12.1 CSS3 给文字添加阴影 使用 text-shadow 属性给页面上的文字添加阴影效果,text-shadow 属性是在CSS2中定义的,在 CSS2.1 中 ...
- 程序猿必备的8款web前端开发插件三
1.HTML5 Canvas 3D波浪翻滚动画 之前我们分享过好几款基于HTML5 Canvas的波浪和水波纹动画,比如这款HTML5 3D波浪起伏动画特效和这款超酷无比的HTML5 WebGL水面水 ...
- [Web 前端] 015 css 三种元素的介绍
1. 块元素,内联元素,内联块元素 元素就是标签 布局中常用的有三种标签 块元素 内联元素 内联块元素 1.1 块元素 也称为行元素 布局中常用的标签,如 div.p.ul.li.h1~h6.dl.d ...
- [Web 前端] 006 css 三种页面引入的方法
1. 外链式 用法 step 1: 在 html 文档的 head 头部分写入下方这句话 <link rel="stylesheet" href="./xxx.cs ...
- web前端学习(三)css学习笔记部分(6)-- 选择器详解
9.选择器详解 9.1 属性选择器 CSS3 属性选择器,在 CSS3 中,追加了三个属性选择器分别为:[att*=val].[att^=val]和[att$=val],使得属性选择器有了通配符的概 ...
随机推荐
- B. Switches and Lamps
链接 [https://codeforces.com/contest/985/problem/B] 题意 给你n,m,分别是n个开关,m个灯 给一个n*m的字符矩阵aij=1,表示i可以控制j这个灯 ...
- pip3 升级失败的解决方法!亲测有效
pip3 --default-timeout=10000 install -U pip 注意:由于防火长城的存在,会导致更新失败,如果你加上--default-timeout=10000 这个就ok ...
- 计算Java List中的重复项出现次数
import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List; ...
- 有界算子p129
? 如果我把这里的1改成2,把1/(a-b) 换成1/2(a-b) 为什么不能是? 2. 这里的x是关于t的函数,为什么x属于 结果了?和x应该没有关系呀? 3. 那为什么T的范数不是一个固定值?为什 ...
- 如何恢复Eclipse中被误删除的文件
在使用Eclipse时,可能会不小心误删除一些文件,没关系,Eclipse有个非常强大的功能,能让这些误删除的文件恢复回来,下面就来介绍一下. 工具/原料 Eclipse Kepler 方法/步骤 ...
- echarts使用笔记二:柱子堆叠
1.多个柱子堆叠效果,多用于各部分占比 app.title = '坐标轴刻度与标签对齐'; option = { title : { //标题 x : 'center', y : 5, text : ...
- Column 'parent_id' specified twice
Hibernate Column 'parent_id' specified twice问题解决--insertable = false, updatable = false的使用 - shendeg ...
- Squid配置之使用帐号密码验证
转自: https://blog.csdn.net/atco/article/details/43448885 1.安装squid使用root用户进行操作.先使用rpm检测是否已经安装了sql ...
- MQ4入门篇(一)
写一个下单功能,和一个平仓功能: 下单: 1:下单使用到的函 int OrderSend(string symbol, int cmd, double volume, double price, in ...
- node 模块化思想中index.js的重要性
目录结构如上图 module1和modlue2.main在同一级 module1下文件: index.js var test2=require('./test2'); var sayHi=functi ...