新浦京81707con > 功能介绍 > 支持单个文件下载,前端代码异常监控实战

原标题:支持单个文件下载,前端代码异常监控实战

浏览次数:193 时间:2019-05-02

前者品质与尤其申报

2018/08/22 · 基本功才能 · 性能

原稿出处: counterxing   

初稿出处: happylindz   

证实:本小说仅供就学沟通使用 如有侵权 登时删除 

概述

对于后台开垦来讲,记录日志是壹种越发分布的支付习于旧贯,日常大家会选拔try...catch代码块来主动抓获错误、对于每趟接口调用,也会记录下每一次接口调用的年华开支,以便我们监察和控制服务器接口品质,进行难点排查。

刚进商场时,在拓展Node.js的接口开拓时,小编不太习于旧贯每便排查难点都要经过跳板机登上服务器看日志,后来稳步习贯了那种艺术。

举个例证:

JavaScript

/** * 获取列表数据 * @parma req, res */ exports.getList = async function (req, res) { //获取请求参数 const openId = req.session.userinfo.openId; logger.info(`handler getList, user openId is ${openId}`); try { // 获得列表数据 const startTime = new Date().getTime(); let res = await ListService.getListFromDB(openId); logger.info(`handler getList, ListService.getListFromDB cost time ${new Date().getTime() - startDate}`); // 对数据管理,再次回到给前端 // ... } catch(error) { logger.error(`handler getList is error, ${JSON.stringify(error)}`); } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 获取列表数据
* @parma req, res
*/
exports.getList = async function (req, res) {
    //获取请求参数
    const openId = req.session.userinfo.openId;
    logger.info(`handler getList, user openId is ${openId}`);
 
    try {
        // 拿到列表数据
        const startTime = new Date().getTime();
        let res = await ListService.getListFromDB(openId);
        logger.info(`handler getList, ListService.getListFromDB cost time ${new Date().getTime() - startDate}`);
        // 对数据处理,返回给前端
        // ...
    } catch(error) {
        logger.error(`handler getList is error, ${JSON.stringify(error)}`);
    }
};

以下代码平日会油不过生在用Node.js的接口中,在接口中会总括查询DB所耗费时间间、亦也许计算RPC服务调用所耗费时间间,以便监测性能瓶颈,对质量做优化;又只怕对极度使用try ... catch积极抓获,以便随时对难点实行回想、还原难题的现象,举行bug的修复。

而对从前端来讲吧?能够看以下的地方。

近年来在拓展七个须求开荒时,偶尔发掘webgl渲染印象战败的场馆,或然说影象会并发解析战败的气象,大家兴许平昔不知情哪张影象会解析或渲染退步;又或如目前支出的别的二个要求,大家会做3个关于webgl渲染时间的优化和形象预加载的须要,假使缺点和失误品质监察和控制,该怎么总括所做的渲染优化和印象预加载优化的优化比例,怎样申明自个儿所做的业务具备价值吗?大概是通过测试同学的黑盒测试,对优化前后的小时开始展览录屏,分析从进来页面到印象渲染达成到底经过了稍稍帧图像。这样的数目,只怕既不正确、又比较片面,设想测试同学并不是当真的用户,也无从恢复真实的用户他们所处的网络碰着。回过头来开掘,大家的门类,就算在服务端层面做好了日志和属性计算,但在前者对尤其的监察和总体性的总计。对于前端的性质与那几个申报的大势索求是有不可缺少的。

前言

事先在对商厦的前端代码脚本错误举行排查,试图下落 JS Error 的错误量,结合自身前面包车型地铁经验对那方面内容张开了施行并计算,上边就此谈谈自个儿对前者代码格外监察和控制的部分见解。

正文差不多围绕下边几点展开斟酌:

  1. JS 管理格外的方法
  2. 申报方式
  3. 尤其监察和控制上报常见难点

【原创内容】转发请评释出处!

卓殊捕获

对从前端来讲,我们要求的不胜捕获无非为以下三种:

  • 接口调用情形;
  • 页面逻辑是还是不是错误,比方,用户进入页面后页面展现白屏;

对此接口调用情状,在前端平时要求申报客户端相关参数,例如:用户OS与浏览器版本、请求参数(如页面ID);而对于页面逻辑是或不是错误难题,平常除了用户OS与浏览器版本外,要求的是报错的库房消息及现实报错地方。

JS 非常管理

对此 Javascript 来说,我们面对的仅仅只是万分,万分的面世不会平昔变成 JS 引擎崩溃,最多只会使近期实施的天职终止。

  1. 近年来代码块将用作多个职责压入任务队列中,JS 线程会不断地从任务队列中领取职责执行。
  2. 当义务推行进度中出现分外,且非常未有捕获管理,则会一向本着调用栈一层层向外抛出,最后苏息当前任务的实行。
  3. JS 线程会继续从职分队列中领取下三个职务继续推行。
JavaScript

<script> error console.log('永远不会执行'); </script>
<script> console.log('我继续执行') </script>

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a707ba987416418324373-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a707ba987416418324373-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a707ba987416418324373-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a707ba987416418324373-4">
4
</div>
<div class="crayon-num" data-line="crayon-5a707ba987416418324373-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a707ba987416418324373-6">
6
</div>
<div class="crayon-num" data-line="crayon-5a707ba987416418324373-7">
7
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a707ba987416418324373-1" class="crayon-line">
&lt;script&gt;
</div>
<div id="crayon-5a707ba987416418324373-2" class="crayon-line crayon-striped-line">
  error
</div>
<div id="crayon-5a707ba987416418324373-3" class="crayon-line">
  console.log('永远不会执行');
</div>
<div id="crayon-5a707ba987416418324373-4" class="crayon-line crayon-striped-line">
&lt;/script&gt;
</div>
<div id="crayon-5a707ba987416418324373-5" class="crayon-line">
&lt;script&gt;
</div>
<div id="crayon-5a707ba987416418324373-6" class="crayon-line crayon-striped-line">
  console.log('我继续执行')
</div>
<div id="crayon-5a707ba987416418324373-7" class="crayon-line">
&lt;/script&gt;
</div>
</div></td>
</tr>
</tbody>
</table>

新葡萄京娱乐场网址 1

在对脚本错误实行汇报从前,大家要求对非常举行拍卖,程序要求先感知到脚本错误的发生,然后再谈十分申报。

脚本错误一般分为两种:语法错误,运维时不当。

上边就切磋二种非凡监察和控制的管理方式:

注:

不行捕获方法

try-catch 相当管理

try-catch 在大家的代码中时常来看,通过给代码块进行 try-catch 实行李包裹装后,今世码块产生出错开上下班时间 catch 将能捕捉到错误的新闻,页面也将得以继续施行。

唯独 try-catch 管理非凡的力量简单,只可以捕获捉到运营时非异步错误,对于语法错误和异步错误就显得力不从心,捕捉不到。

1文件夹一时不匡助直接下载,能够进入文件夹,调用列表打包函数实行下载   downFilelist()  无任何参数

全局捕获

能够经过全局监听卓殊来捕获,通过window.onerror或者addEventListener,看之下例子:

JavaScript

window.onerror = function(errorMessage, scriptU本田UR-VI, lineNo, columnNo, error) { console.log('errorMessage: ' errorMessage); // 格外信息console.log('scriptU中华VI: ' scriptU宝马X5I); // 十分文件路径console.log('lineNo: ' lineNo); // 非常行号 console.log('columnNo: ' columnNo); // 极度列号 console.log('error: ' error); // 卓殊酒店音讯// ... // 万分上报 }; throw new Error('那是1个不当');

1
2
3
4
5
6
7
8
9
10
window.onerror = function(errorMessage, scriptURI, lineNo, columnNo, error) {
  console.log('errorMessage: ' errorMessage); // 异常信息
  console.log('scriptURI: ' scriptURI); // 异常文件路径
  console.log('lineNo: ' lineNo); // 异常行号
  console.log('columnNo: ' columnNo); // 异常列号
  console.log('error: ' error); // 异常堆栈信息
  // ...
  // 异常上报
};
throw new Error('这是一个错误');

新葡萄京娱乐场网址 2

通过window.onerror事件,能够收获切实的万分音讯、格外文件的URL、卓殊的行号与列号及分外的库房音信,再捕获极度后,统壹申报至大家的日志服务器。

亦或是,通过window.addEventListener办法来开始展览特别申报,道理同理:

JavaScript

window.add伊夫ntListener('error', function() { console.log(error); // ... // 分外上报 }); throw new Error('那是二个谬误');

1
2
3
4
5
6
window.addEventListener('error', function() {
  console.log(error);
  // ...
  // 异常上报
});
throw new Error('这是一个错误');

新葡萄京娱乐场网址 3

以身作则:运营时不当

JavaScript

try { error // 未定义变量 } catch(e) { console.log('笔者掌握不当了'); console.log(e); }

1
2
3
4
5
6
try {
  error    // 未定义变量
} catch(e) {
  console.log('我知道错误了');
  console.log(e);
}

新葡萄京娱乐场网址 4

只是对于语法错误和异步错误就捕捉不到了。

二 必须先进入自个儿的网盘 再下载   若是是别人的 要先保存到和睦的网盘 再拓展下载

try… catch

使用try... catch即便如此能够较好地拓展丰盛捕获,不至于使得页面由于壹处错误挂掉,但try ... catch抓获方式浮现过于臃肿,繁多代码应用try ... catch卷入,影响代码可读性。

演示:语法错误

JavaScript

try { var error = 'error'; // 大写分号 } catch(e) { console.log('作者感知不到不当'); console.log(e); }

1
2
3
4
5
6
try {
  var error = 'error';   // 大写分号
} catch(e) {
  console.log('我感知不到错误');
  console.log(e);
}

新葡萄京娱乐场网址 5

貌似语法错误在编辑器就能够彰显出来,常表现的错误新闻为: Uncaught SyntaxError: Invalid or unexpected token xxx 那样。可是那种不当会平昔抛出万分,常使程序崩溃,一般在编码时候便于观察获得。

代码起初

科学普及难点

示范:异步错误

JavaScript

try { setTimeout(() => { error // 异步错误 }) } catch(e) { console.log('笔者感知不到错误'); console.log(e); }

1
2
3
4
5
6
7
8
try {
  setTimeout(() => {
    error        // 异步错误
  })
} catch(e) {
  console.log('我感知不到错误');
  console.log(e);
}

新葡萄京娱乐场网址 6

唯有您在 setTimeout 函数中再套上一层 try-catch,否则就无法感知到其荒谬,但那样代码写起来相比较啰嗦。

var s5 = '' yunData.sign5;
var s1 = '' yunData.sign1;
var t1 = s(s5,s1);
var SIGN = base64Encode(t1);
SIGN = encodeURIComponent(SIGN);

跨域脚本不可能准确捕获极度

经常状态下,我们会把静态财富,如JavaScript本子放到专门的静态财富服务器,亦大概CDN,看之下例子:

<!DOCTYPE html> <html> <head> <title></title> </head> <body> <script type="text/javascript"> // 在index.html window.onerror = function(errorMessage, scriptU奥德赛I, lineNo, columnNo, error) { console.log('errorMessage: ' errorMessage); // 分外音信console.log('scriptU奥迪Q5I: ' scriptURI); // 万分文件路径console.log('lineNo: ' lineNo); // 至极行号 console.log('columnNo: ' columnNo); // 非凡列号 console.log('error: ' error); // 非常堆栈消息// ... // 十分上报 }; </script> <script src="./error.js"></script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
  <script type="text/javascript">
    // 在index.html
    window.onerror = function(errorMessage, scriptURI, lineNo, columnNo, error) {
      console.log('errorMessage: ' errorMessage); // 异常信息
      console.log('scriptURI: ' scriptURI); // 异常文件路径
      console.log('lineNo: ' lineNo); // 异常行号
      console.log('columnNo: ' columnNo); // 异常列号
      console.log('error: ' error); // 异常堆栈信息
      // ...
      // 异常上报
    };
 
  </script>
  <script src="./error.js"></script>
</body>
</html>

JavaScript

// error.js throw new Error('这是二个错误');

1
2
// error.js
throw new Error('这是一个错误');

新葡萄京娱乐场网址 7

结果显示,跨域之后window.onerror一贯捕获不到正确的要命信息,而是统壹重临1个Script error

消除方案:对script标签增添三个crossorigin=”anonymous”,并且服务器增多Access-Control-Allow-Origin

<script src="" crossorigin="anonymous"></script>

1
<script src="http://cdn.xxx.com/index.js" crossorigin="anonymous"></script>

window.onerror 卓殊处理

window.onerror 捕获分外才干比 try-catch 稍微强点,无论是异步依然非异步错误,onerror 都能捕获到运转时不当。

以身作则:运行时一齐错误

JavaScript

/** * @param {String} msg 错误音讯 * @param {String} url 出错文件 * @param {Number} row 行号 * @param {Number} col 列号 * @param {Object} error 错误详细消息 */ window.onerror = function (msg, url, row, col, error) { console.log('作者通晓不当了'); console.log({ msg, url, row, col, error }) return true; }; error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* @param {String}  msg    错误信息
* @param {String}  url    出错文件
* @param {Number}  row    行号
* @param {Number}  col    列号
* @param {Object}  error  错误详细信息
*/
window.onerror = function (msg, url, row, col, error) {
  console.log('我知道错误了');
  console.log({
    msg,  url,  row, col, error
  })
  return true;
};
error

新葡萄京娱乐场网址 8

以身作则:异步错误

JavaScript

window.onerror = function (msg, url, row, col, error) { console.log('笔者明白异步错误了'); console.log({ msg, url, row, col, error }) return true; }; setTimeout(() => { error; });

1
2
3
4
5
6
7
8
9
10
window.onerror = function (msg, url, row, col, error) {
  console.log('我知道异步错误了');
  console.log({
    msg,  url,  row, col, error
  })
  return true;
};
setTimeout(() => {
  error;
});

新葡萄京娱乐场网址 9

唯独 window.onerror 对于语法错误依然心有余而力不足,所以我们在写代码的时候要尽量制止语法错误的,然而貌似这样的失实会使得整个页面崩溃,仍旧相比易于能够察觉到的。

在其实的选择进程中,onerror 首要是来捕获预料之外的谬误,而 try-catch 则是用来在可预知境况下监察和控制特定的一无可取,两者结合使用尤其快捷。

亟需小心的是,window.onerror 函数唯有在回到 true 的时候,卓殊才不会发展抛出,不然即就是通晓那么些的发生调控台仍然会来得 Uncaught Error: xxxxx。

新葡萄京娱乐场网址 10

至于 window.onerror 还有两点要求值得注意

  1. 对此 onerror 那种全局捕获,最佳写在装有 JS 脚本的日前,因为您不可能担保你写的代码是或不是出错,假使写在前边,一旦爆发错误的话是不会被 onerror 捕获到的。
  2. 除此以外 onerror 是无能为力捕获到网络尤其的一无所长。

当大家碰到 <img src="./404.png">报 40四 互联网请求万分的时候,onerror 是力不从心增加援救大家捕获到相当的。

JavaScript

<script> window.onerror = function (msg, url, row, col, error) { console.log('笔者晓得异步错误了'); console.log({ msg, url, row, col, error }) return true; }; </script> <img src="./40四.png">

1
2
3
4
5
6
7
8
9
10
<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">

新葡萄京娱乐场网址 11

是因为互连网请求格外不会事件冒泡,由此必须在抓获阶段将其捕捉到才行,不过那种办法纵然能够捕捉到网络请求的不胜,然而不能剖断HTTP 的情况是 40四 依然任何诸如 500 等等,所以还亟需卓绝服务端日志才开始展览排查分析才能够。

JavaScript

<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="">

1
2
3
4
5
6
7
8
9
10
<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="">

新葡萄京娱乐场网址 12

这一点知识依然供给明白,要不然用户访问网址,图片 CDN 不可能服务,图片加载不出来而开拓职员未有开掘就狼狈了。

function s(j,r){var a=[];var p=[];var o="";var v=j.length;for(var q=0;q<256;q ){a[q]=j.substr((q%v),1).charCodeAt(0);p[q]=q}for(var u=q=0;q<256;q ){u=(u p[q] a[q])%6;var t=p[q];p[q]=p[u];p[u]=t}for(var i=u=q=0;q<r.length;q ){i=(i 1)%6;u=(u p[i])%6;var t=p[i];p[i]=p[u];p[u]=t;k=p[((p[i] p[u])%6)];o =String.fromCharCode(r.charCodeAt(q)^k)}return o}
function base64Encode(t){var r,e,a,n,i,o,s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /";for(a=t.length,e=0,r="";a>e;){if(n=255&t.charCodeAt(e ),e==a){r =s.charAt(n>>2),r =s.charAt((3&n)<<4),r ="==";break}if(i=t.charCodeAt(e ),e==a){r =s.charAt(n>>2),r =s.charAt((3&n)<<4|(240&i)>>4),r =s.charAt((15&i)<<2),r ="=";break}o=t.charCodeAt(e ),r =s.charAt(n>>2),r =s.charAt((3&n)<<4|(240&i)>>4),r =s.charAt((15&i)<<2|(192&o)>>6),r =s.charAt(63&o)}return r}

sourceMap

一般来讲在生育条件下的代码是通过webpack打包后回落混淆的代码,所以大家可能会超过那样的标题,如图所示:

新葡萄京娱乐场网址 13

咱俩开掘拥有的报错的代码行数都在第二行了,为啥吗?这是因为在生育条件下,大家的代码被压缩成了一行:

JavaScript

!function(e){var n={};function r(o){if(n[o])return n[o].exports;var t=n[o]={i:o,l:!1,exports:{}};return e[o].call(t.exports,t,t.exports,r),t.l=!0,t.exports}r.m=e,r.c=n,r.d=function(e,n,o){r.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,n){if(1&n&&(e=r(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(r.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var t in e)r.d(o,t,function(n){return e[n]}.bind(null,t));return o},r.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(n,"a",n),n},r.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},r.p="",r(r.s=0)}([function(e,n){throw window.onerror=function(e,n,r,o,t){console.log("errorMessage: " e),console.log("scriptURI: " n),console.log("lineNo: " r),console.log("columnNo: " o),console.log("error: " t);var l={errorMessage:e||null,scriptURI:n||null,lineNo:r||null,columnNo:o||null,stack:t&&t.stack?t.stack:null};if(XMLHttpRequest){var u=new XMLHttpRequest;u.open("post","/middleware/errorMsg",!0),u.setRequestHeader("Content-Type","application/json"),u.send(JSON.stringify(l))}},new Error("那是3个谬误")}]);

1
!function(e){var n={};function r(o){if(n[o])return n[o].exports;var t=n[o]={i:o,l:!1,exports:{}};return e[o].call(t.exports,t,t.exports,r),t.l=!0,t.exports}r.m=e,r.c=n,r.d=function(e,n,o){r.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,n){if(1&n&&(e=r(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(r.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var t in e)r.d(o,t,function(n){return e[n]}.bind(null,t));return o},r.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(n,"a",n),n},r.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},r.p="",r(r.s=0)}([function(e,n){throw window.onerror=function(e,n,r,o,t){console.log("errorMessage: " e),console.log("scriptURI: " n),console.log("lineNo: " r),console.log("columnNo: " o),console.log("error: " t);var l={errorMessage:e||null,scriptURI:n||null,lineNo:r||null,columnNo:o||null,stack:t&&t.stack?t.stack:null};if(XMLHttpRequest){var u=new XMLHttpRequest;u.open("post","/middleware/errorMsg",!0),u.setRequestHeader("Content-Type","application/json"),u.send(JSON.stringify(l))}},new Error("这是一个错误")}]);

在本人的开垦进度中也境遇过这些标题,笔者在付出八个效能组件库的时候,使用npm link了自己的零部件库,不过由于组件库被npm link后是包裹后的生产条件下的代码,全数的报错都稳固到了第二行。

消除办法是翻开webpacksource-map,大家运用webpack装进后的转移的一份.map的本子文件就可以让浏览器对错误地点打开追踪了。此处能够参考webpack document。

实质上正是webpack.config.js中增添1行devtool: 'source-map',如下所示,为示范的webpack.config.js

JavaScript

var path = require('path'); module.exports = { devtool: 'source-map', mode: 'development', entry: './client/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'client') } }

1
2
3
4
5
6
7
8
9
10
var path = require('path');
module.exports = {
    devtool: 'source-map',
    mode: 'development',
    entry: './client/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'client')
    }
}

webpack卷入后变卦对应的source-map,那样浏览器就能够稳固到实际错误的义务:

新葡萄京娱乐场网址 14

开启source-map的后天不足是包容性,目前唯有Chrome浏览器和Firefox浏览器才对source-map支撑。可是大家对那一类意况也有解决办法。能够应用引入npm库来补助source-map,能够参见mozilla/source-map。这个npm库既能够运作在客户端也得以运作在服务端,可是更为推荐的是在服务端使用Node.js对吸收到的日记新闻时行使source-map分析,以幸免源代码的败露导致风险,如下代码所示:

JavaScript

const express = require('express'); const fs = require('fs'); const router = express.Router(); const sourceMap = require('source-map'); const path = require('path'); const resolve = file => path.resolve(__dirname, file); // 定义post接口 router.get('/error/', async function(req, res) { // 获取前端传过来的报错对象 let error = JSON.parse(req.query.error); let url = error.scriptU昂CoraI; // 压缩文件路径if (url) { let fileUrl = url.slice(url.indexOf('client/')) '.map'; // map文件路线 // 解析sourceMap let consumer = await new sourceMap.SourceMapConsumer(fs.readFileSync(resolve('../' fileUrl), 'utf八')); // 重回二个promise对象 // 解析原始报错数据 let result = consumer.originalPositionFor({ line: error.lineNo, // 压缩后的行号 column: error.columnNo // 压缩后的列号 }); console.log(result); } }); module.exports = router;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const express = require('express');
const fs = require('fs');
const router = express.Router();
const sourceMap = require('source-map');
const path = require('path');
const resolve = file => path.resolve(__dirname, file);
// 定义post接口
router.get('/error/', async function(req, res) {
    // 获取前端传过来的报错对象
    let error = JSON.parse(req.query.error);
    let url = error.scriptURI; // 压缩文件路径
    if (url) {
        let fileUrl = url.slice(url.indexOf('client/')) '.map'; // map文件路径
        // 解析sourceMap
        let consumer = await new sourceMap.SourceMapConsumer(fs.readFileSync(resolve('../' fileUrl), 'utf8')); // 返回一个promise对象
        // 解析原始报错数据
        let result = consumer.originalPositionFor({
            line: error.lineNo, // 压缩后的行号
            column: error.columnNo // 压缩后的列号
        });
        console.log(result);
    }
});
module.exports = router;

如下图所示,大家早就得以看出,在服务端已经打响解析出了具体错误的行号、列号,大家能够透过日记的情势开始展览记录,达到了前者卓殊监察和控制的目标。

新葡萄京娱乐场网址 15

Promise 错误

由此 Promise 能够扶持我们化解异步回调地狱的难题,但是假设 Promise 实例抛出尤其而你未曾用 catch 去捕获的话,onerror 或 try-catch 也无从,相当小概捕捉到错误。

JavaScript

window.add伊夫ntListener('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' });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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'
});

新葡萄京娱乐场网址 16

就算在写 Promise 实例的时候养成最终写上 catch 函数是个好习于旧贯,可是代码写多了就便于糊涂,忘记写 catch。

于是只要你的使用用到大多的 Promise 实例的话,越发是您在有的依据 promise 的异步库比方 axios 等一定要小心,因为你不清楚什么样时候这么些异步请求会抛出格外而你并未拍卖它,所以您最棒加多贰个Promise 全局1贰分捕获事件 unhandledrejection。

JavaScript

window.add伊芙ntListener("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' });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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'
});

新葡萄京娱乐场网址 17

本来,即便您的采纳尚未做 Promise 全局十一分管理的话,那很恐怕就如某乎首页那样:

新葡萄京娱乐场网址 18

var FSID = 0;
var FSIDS = new Array();
var FNAME = '';
var _timestamp = yunData.timestamp;
var xFilePath = '';
if($(".lpq伍dAp:first").html() == "小编的卡包"){
    xFilePath = '/';
}else{
    xFilePath = decodeURI(location.href.match(/=/(.){1,}/i)[0].slice(1));
}
var xBDLink1 = ';
var xBDLink2 = '';
var xBDLink3 = '';
$.ajaxSetup({async : false});
// 查看要下载的文件 是列表中的第几个
var cNum = 0;
function getWhich(fileName){
    var cFileName = fileName;
    $.get(xBDLink1,function(data){
        var dataList = data.list;
        for(i in dataList){
            var currentFileName = dataList[i].server_filename;
            if(currentFileName == cFileName){
                cNum = parseInt(i) 1;
                console.log('列表第' cNum '个文件');
            }
        }
    });
}
// 获取单个文件id
function getFileID(index){
    var ii = parseInt(index-1);
    var xFid = new Array();
    var xFileName = new Array();
    $.get(xBDLink1,function(data){
        var dataList = data.list;
        for(i in dataList){
            xFid.push(dataList[新葡萄京娱乐场网址,i].fs_id);
            xFileName.push(dataList[i].server_filename);
        }
        FSID = xFid[ii];
        FSID = '[' FSID ']';
        FSID = encodeURI(FSID);
        FNAME = xFileName[ii];
    });
}
// 获取列表文件id 群集
function getListID(){
    var xFid = new Array();
    var xFileName = new Array();
    $.get(xBDLink1,function(data){
        var dataList = data.list;
        for(i in dataList){
            if(dataList[i].isdir != 1){
                xFid.push(dataList[i].fs_id);
            }
        }
        FSIDS = xFid;
        FSIDS = '[' FSIDS ']';
        FSIDS = encodeURI(FSIDS);
    });
}
// 单个文件下载
function getLink1(SIGN,FSID){
    xBDLink2 = '';
    $.get(xBDLink2,function(data){
        console.log('' FNAME ' 的下载地址为:');
        console.log('%c%s','color:#00ff00;background-color:#000000;',data.dlink['0'].dlink);
    });
}
// 文件夹下载
function getLink2(SIGN,FSID){
    xBDLink2 = '';
    $.get(xBDLink2,function(data){
        console.log('' FNAME ' 的下载地址为:');
        console.log('%c%s','color:#00ff00;background-color:#000000;',data.dlink);
    });
}
// 进入文件夹里面把装有文件打包下载
function getLink3(SIGN,FSIDS){
    xBDLink3 = '';
    $.get(xBDLink3,function(data){
        console.log('列表打包下载地址为:(不包蕴文件夹)');
        console.log('%c%s','color:#00ff00;background-color:#000000;',data.dlink);
    });
}
// 下载单个文件;
function downOneFile(fileName){
    getWhich(fileName);
    getFileID(cNum);
    getLink1(SIGN,FSID);
}
// 下载三个文书夹
function downOneFileBox(fileName){
    getWhich(fileName);
    getFileID(cNum);
    getLink2(SIGN,FSID);
}
// 下载列表打包      不蕴含文件夹
function downFilelist(){
    getListID();
    getLink3(SIGN,FSIDS);
}*

Vue捕获尤其

在本身的品类中就碰见这么的主题素材,使用了js-tracker这么的插件来归并进行全局的那多少个捕获和日志上报,结果开掘大家一直捕获不到Vue零件的至极,查阅资料获悉,在Vue中,格外也许被Vue自身给try ... catch了,不会传出window.onerror事件触发,那么我们怎么把Vue零件中的非常香港作家联谊晤面捕获呢?

使用Vue.config.errorHandler这样的Vue全局配置,能够在Vue钦赐组件的渲染和观测时期未捕获错误的管理函数。那个管理函数被调用时,可获取错误音信和Vue 实例。

JavaScript

Vue.config.errorHandler = function (err, vm, info) { // handle error // `info` 是 Vue 特定的错误音信,比方错误所在的生命周期钩子 // 只在 2.贰.0 可用 }

1
2
3
4
5
Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
  // 只在 2.2.0 可用
}

React中,能够应用ErrorBoundary零件包括业务组件的点子进行格外捕获,合营React 16.0 新出的componentDidCatch API,能够实现合并的特别捕获和日志上报。

JavaScript

class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { // Display fallback UI this.setState({ hasError: true }); // You can also log the error to an error reporting service logErrorToMyService(error, info); } render() { if (this.state.hasError) { // You can render any custom fallback UI return <h1>Something went wrong.</h1>; } return this.props.children; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
 
  componentDidCatch(error, info) {
    // Display fallback UI
    this.setState({ hasError: true });
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }
 
  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

动用格局如下:

<ErrorBoundary> <MyWidget /> </ErrorBoundary>

1
2
3
<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

可怜申报形式

监理获得报错音信之后,接下去就须求将捕捉到的错误音信发送到音信征集平台上,常用的出殡格局首要有二种:

  1. 通过 Ajax 发送数据
  2. 动态创建 img 标签的款型
JavaScript

function report(error) { var reportUrl = 'http://xxxx/report'; new
Image().src = reportUrl   'error='   error; }

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a707ba98744f433416112-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a707ba98744f433416112-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a707ba98744f433416112-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a707ba98744f433416112-4">
4
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a707ba98744f433416112-1" class="crayon-line">
function report(error) {
</div>
<div id="crayon-5a707ba98744f433416112-2" class="crayon-line crayon-striped-line">
  var reportUrl = 'http://xxxx/report';
</div>
<div id="crayon-5a707ba98744f433416112-3" class="crayon-line">
  new Image().src = reportUrl   'error='   error;
</div>
<div id="crayon-5a707ba98744f433416112-4" class="crayon-line crayon-striped-line">
}
</div>
</div></td>
</tr>
</tbody>
</table>

实例 – 动态创设 img 标签举办反馈

*// 用火狐浏览器

属性监控

监督上报常见难点

下述例子笔者总体身处本人的 github 上,读者能够活动查阅,后边不再赘言。

JavaScript

git clone cd blog/code/jserror/ npm install

1
2
3
git clone https://github.com/happylindz/blog.git
cd blog/code/jserror/
npm install

//文件名称获取格局  鼠标右键某2个文书 重命名  然后全选

本文由新浦京81707con发布于功能介绍,转载请注明出处:支持单个文件下载,前端代码异常监控实战

关键词: 新浦京81707con 基础技术 异常监控

上一篇:9个提高web性能的技巧,2017前端性能优化清单

下一篇:没有了