监控数据上报异常排查
上报数据方式
1、利用图片不受跨域限制,使用图片的src赋值上报
2、使用ajax上报数据
3、使用sendBeacon上传数据
查阅优劣分析之后:https://blog.csdn.net/a460550542/article/details/127709806
团队采用sendBeacon上报
背景
活动模板每个商品的发出一次询价请求,在运维nginx的数据和前端上报的数据不一致,nginx出现多出一倍的数据,
现网表现为
数据量为 308k,远远超过了chrome限制的64k,
解决方式1
对大数据量做切割,每次切30k的数据,代码思路如下
1 const report = { 2 ... 3 spiltData(dataList, limit = 64) { 4 const sizeArr = dataList.map(v => report.getStringSizeInKB(JSON.stringify(v))); 5 let prevTotal = 0, 6 sliceArr = [], 7 currentArr = []; 8 sizeArr.forEach((v, i) => { 9 const currentTotal = prevTotal + v; 10 const currentData = dataList[i]; 11 if (v > limit) { 12 sliceArr.push(currentData) 13 return 14 } 15 if (prevTotal < limit && currentTotal >= limit) { 16 sliceArr.push(currentArr.splice(0)) 17 currentArr = [currentData] 18 prevTotal = v 19 } else { 20 prevTotal = currentTotal; 21 currentArr.push(currentData) 22 } 23 }) 24 sliceArr.push(currentArr.splice(0)) 25 return sliceArr 26 }, 27 getStringSizeInKB(str) { 28 var utf8Length = encodeURI(str).split(/%..|./).length - 1; 29 var size = utf8Length / 1024; 30 return parseFloat(size.toFixed(2)); 31 }, 32 }
由于navigator.sendBeacon并没上报回调,因此采用setTimeout调度请求,每隔500ms发一次数据,代码实现思路如下
1 const report = { 2 ... 3 sendBeacon(url, data) { 4 if (navigator.sendBeacon) { 5 // 解决sendBeacon64k限制 6 const dataList = this.spiltData(data.data, 20); 7 this.excuteSend(url, dataList) 8 } else { 9 this.ajaxPost(url, data) 10 } 11 }, 12 peddingDataList: [], 13 excuteSend(url, dataList) { 14 let timeout = null, 15 result = true, 16 errorTimes = 0; 17 report.peddingDataList = [ 18 ...report.peddingDataList, 19 ...dataList 20 ]; 21 22 function checkSend() { 23 if (result || errorTimes > 2) { 24 const dataList = report.peddingDataList.splice(0, 1)[0] 25 result = navigator.sendBeacon(url, JSON.stringify({ 26 data: [...dataList] 27 })); 28 errorTimes = 0; 29 } else { 30 errorTimes++ 31 } 32 timeout = setTimeout(() => { 33 if (report.peddingDataList.length > 0) { 34 checkSend(); 35 } else { 36 clearTimeout(report.timeout) 37 } 38 }, 1000) 39 } 40 checkSend(); 41 }, 42 }
部署之后表现并不佳,发现数据依然有很多没完成上报
解决方式2
将较大数据量的上报数据使用ajax上报,小的数据则使用navigator.sendBeacon,
考虑到数据可能会太大,分析之后大数据量主要是页面ajax请求相关的数据,在ajax请求模块,在数据量超过60条之后则立刻执行上报,思路如下
1 function logEntries(entries = []) { 2 const xhrEntries = entries.filter(i => i.initiatorType === 'xmlhttprequest'); 3 cgiList.forEach((item) => { 4 if (!item.url) { 5 return 6 } 7 const entry = xhrEntries.find(i => i.name.includes(item.url)); 8 if (!entry) return; 9 item.runSide = 'client'; 10 }); 11 if (cgiList.length > 60) { 12 reportCgi() 13 } else { 14 utils.throttle(reportCgi, this, 500); 15 } 16 }
根据数据分析,在20条数据时候,上报数据约为20K,在粗略分析之后,阈值设置为20条,当数据超过20条之后,则使用ajax上报,否则使用navigator.sendBeacon
实现思路如下
1 const report = { 2 ... 3 sendBeacon(url, data) { 4 // 解决sendBeacon64k限制, 5 // 数据量大约1个1K,大于20个则使用ajax,避免sendBeacon失败 6 this.wafData(data) 7 if (navigator.sendBeacon && data.data.length < 20) { 8 navigator.sendBeacon(url, JSON.stringify(data)); 9 } else { 10 this.ajaxPost(url, data) 11 } 12 }, 13 ajaxPost(url, data, cb) { 14 const xhr = new XMLHttpRequest(); 15 const jsonData = JSON.stringify(data); 16 xhr.onreadystatechange = function() { 17 if (xhr.readyState === 4 && xhr.status === 200) { 18 const res = JSON.parse(xhr.responseText) 19 cb && cb(res) 20 } 21 } 22 xhr.open('POST', url); 23 xhr.setRequestHeader("Content-Type", "application/json"); 24 xhr.send(jsonData); 25 }, 26 }
部署之后表现如下
能够正常上报