代码中 throw new Error
Aegis SDK 没有捕获到,该如何处理?
在 VUE 框架中,Vue.config.errorHandler 会主动捕获错误,可以通过主动捕获再调用 aegis.error() 进行上报。
为什么接入 SDK 后没有数据?
没有数据可以从以下方向查找问题:
1. 查看上报接口(aegis.qq.com)返回是否正常,正常返回 200 和 204,如果接口返回 403 可以看下一个问题。
2. 看日志查询里面页面访问和历史是否有数据,如果没有数据,有可能是上报延迟导致(1-2min)。
3. 数据总览里面的数据是每整数小时计算一次,如果没有数据可以看下是否上个小时没有页面访问,或者新接入还没开始计算。
4. 如果是页面性能没有数据,或者缺少数据,可以看下 network 中上报接口 performance 中的 firstScreenTiming 的值,如果这个值为0,或者大于15s,就会导致页面性能缺少数据。
解决办法:把 sdk 初始化尽可能放在代码最前面,可以考虑用 cdn 并且在 head 中初始化代码,尤其对于一些 SSR 的页面,因为页面首屏时间较小,初始化 sdk 过晚会导致无法采集到页面首屏信息。
5. 对于日志中没有数据,尤其刚刚接入的应用,因为 Aegis SDK 默认只采集错误日志,例如接口报错、js 错误、promise 错误等,所以刚刚接入会看不到日志。开发者可以主动上报一些日志(aegis.infoAll、aegis.report等),看是否有数据。如果有需要,也可以开启全量接口上报(api.reportRequest),查看上报的接口的信息。
前端监控里面统计到的接口耗时(静态资源耗时)跟后端统计的相差很远,可能是什么原因导致的?
1. 用户网络出问题,请求没有发送到后端,耗时比较久后失败了。
2. 用户请求发出了,但是中间网络层耗时比较久,后端处理很快,过了很久才返回给用户。
3. 用户看的是平均值,可能由于某个或者某几个用户出现比较高的异常值导致整体值偏低,用户可以看下中位数是否依然异常。
4. 用户请求接口(静态资源)受多方面因素影响,网络、地域、设备都会对最终值产生影响,cdn 没有预热,dns 第一次解析耗时比较久等原因都会导致前后端统计不一致,前端性能监控通过浏览器的 performance 对象获取这些耗时并且进行上报。
5. 前端性能监控只是把这个耗时记录下来,并不对这个耗时负责。
接口请求报错 403 该如何处理?
说明:
如果不确定您的上报域名,可以在浏览器控制台输入
location.host
查看。对于非 web 应用,默认填入 *
表示不需要校验。用户在 RUM 上创建应用后,会得到一个长度为 18 位的字符串,这个字符串为上报 ID,new Aegis 的时候传入的 ID 就是这个上报 ID。如果这个 ID 不正确,也会报错 403。
Aegis 初始化
new Aegis({id: 'pGUVFTCZyewhxxxxxx'})
说明:
如果应用刚创建,RUM 数据同步需要一定的时间,大概在1-2min。
上报域名错误也会导致接口返回 403 。用户需要注意使用区域,不同区域的上报域名是不一样的。
国内(广州):https://rumt-zh.com
新加坡:https://rumt-sg.com
硅谷:https://rumt-us.com
除此之外,用户初始化 Aegis SDK 的时候传入异常的参数也会导致接口返回 403,例如 uin 限制字符串正则为
/^[@=.0-9a-zA-Z_-]{1,60}$/
具体每个参数的限制可参见 配置文档。日志里出现“图片加载失败”、“JS 加载失败”、“CSS 加载失败” 的问题该如何排查?
1. 自行访问一下资源,查看是否有异常情况。
2. 若访问正常,但是日志里面还是有比较多的异常情况。
3. 再查看一下这些异常是否有聚集的情况,例如区域聚集,运营商聚集等。
4. 若没有发现有聚集的情况,那大概率是因为用户的网络问题导致的资源加载异常,可以尝试应用中接入 PWA 或者离线包来减少这类情况。本质上,前端没有办法完全避免这种情况。
应用接入 SDK 后,为什么会有一个 aegis.qq.com/speed/webvitals
的接口在页面刷新的时候 cancel ?
webvitals 中 CLS 的值必须是页面可见性改变的时候才计算的,用户刷新页面的时候,如果选中了 Preserve log,就会有一条请求处理发送中,但恰好被页面刷新给 cancel 掉,就出现这种情况。对用户和数据没有影响,可以忽略。
有不少错误日志是 “Script error. @ (:0:0) 没啥信息” 这种是第三方 JS 异常吗?可以通过配置过滤掉吗?
Script error. 也被称为跨域错误,当网站请求并且执行一个非本域名下的脚本的时候,如果跨域脚本发生错误,就有可能抛出这个错误。由于应用中,我们的脚本都是放在 CDN 上的,因此这种错误最为常见。
其实这并不是一个 JavaScript Bug。但出于安全考虑,浏览器会刻意隐藏其他域的 JS 文件抛出的具体错误信息,这样做可以有效避免敏感信息无意中被不受控制的第三方脚本捕获。因此浏览器只允许同域下的脚本捕获具体错误信息,而其他脚本只知道发生了一个错误,但无法获知错误的具体内容。更多信息,请参见 Webkit 源码。
具体解决方式:
解决办法1:CORS
假如您页面所在的域名为 "https://domain.com",CDN 地址为 "https://another-domain.com/app.js",下面为您介绍如何通过配置参数过滤掉 "Script error. @ (:0:0) " 错误信息。
步骤1:资源添加 crossorigin 属性。
<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>
步骤2:CDN 添加 cors 响应头,这个基本是 cdn 默认的,所以实际上我们并不需要做什么。
Access-Control-Allow-Origin: *
解决办法2: try catch
window.onerror 中只能捕获
Script error.
,但是 try catch 中却能打印详细的错误栈。<!doctype html><html><body><script src="http://another-domain.com/app.js"></script><script>window.onerror = function (message, url, line, column, error) {console.log(message, url, line, column, error);}try {foo(); // 调用app.js中定义的foo方法} catch (e) {console.log(e);throw e; // 主动抛出的错误捕获后不是 Script error}</script></body></html>
如果不想解决,只想直接屏蔽,可以参考下一个问题,不上报特殊日志。
对于一些特殊的日志,不想上报到 RUM,可以如何处理?
SDK 提供一个 hook 来帮助用户在日志上报前对日志进行屏蔽和修改,可以使用 beforeRequest,返回 false 就可以不上报该条日志,返回修改过后的 data 就可以实现对上报数据的修改。
beforeRequest
new Aegis({id: 'pGUVFTCZyewhxxxxxx',beforeRequest(data) {// 入参data的数据结构:{logs: {…}, logType: "log"}if (data.logType === 'log' && data.logs.msg.indexOf('otheve.beacon.qq.com') > -1) {// 拦截:日志类型为 log,且内容包含 otheve.beacon.qq.com 的请求return false;}// 入参data数据结构:{logs: {}, logType: "speed"}if (data.logType === 'speed' && data.logs.url.indexOf('otheve.beacon.qq.com') > -1) {// 拦截:日志类型为 speed,并且接口 url 包含 otheve.beacon.qq.com 的请求return false;}if (data.logType === 'performance') {// 修改:将性能数据的首屏渲染时间改为2sdata.logs.firstScreenTiming = 2000;}return data;}})
SDK 如何获取网络类型?为什么我的网络类型不正确?
若 UA 里面有 NetType ,则 UA 是从 NetType 获取的。若没有,您用的是
navigator.connection.effectiveType || navigator.connection.type
,effectiveType
,则会根据您的网速推算出的一个类型,并不是实际类型。为什么 SDK 上报的接口请求耗时跟 network 里面的时间不一致?
SDK 通过劫持 fetch 和 xhr 的方式实现对接口的测速,在请求前和请求后分别进行打点测速,因为 JS 计算时间差的逻辑依赖 js 主线程执行,如果 end 时间执行的时候有线程阻塞,会导致实际计算的时长要大于浏览器 network 时长。
为什么上报的网络类型跟实际网络类型不符合,例如当前用户使用的是 wifi,上报的却是 4G?
我们目前通过 UA 里面的 NetType 和
navigator.connection.effectiveType
获取网络类型,前者依赖浏览器注入网络信息到 UA,后者是浏览器提供的 “等效网络类型”,并不代表真实的网络类型。navigator.connection.effectiveType
这个 API 目前还存在兼容性问题,iOS 暂不支持,所以会被识别为未知。开启了 SPA 参数,但是页面之间跳转的时候,为什么没有上报页面性能?
SPA 页面之间的跳转,本质上只是一段 JS 代码的执行,首屏探测的是从用户浏览器发起请求到页面可见元素渲染完成的时间,因此没有办法计算首屏。
日志里面上报了非常多 AJAX 异常,状态码是 0 ,可能是什么原因导致的?
HTTP 接口的 status 是 0,有以下几种可能:超时、abort、cancel、跨域。Aegis SDK 已经默认屏蔽了 XHR 请求的 abort 请求,但是 Fetch 请求的 abort 还有静态资源的 abort 没有办法识别和屏蔽。
开发者本地调试可能没有发现这种错误,但为什么在用户侧却能经常发生?
因为用户侧可能随时离开页面,或者因为网络问题把某次 HTTP 请求中断了,这种情况就会发生 status 为 0 的情况。
虽然 status 为 0 有多种情况,但我们也可以根据日志里面的信息看出一些问题。例如上述截图里面的耗时都非常小,而且发生的用户比较集中,因此可以判断该接口是浏览器插件屏蔽掉了,这种情况常见于一些数据上报的接口。
如果看到 duration 非常长,那超时的可能性就比较大了,开发者也可以查看自己接口的超时时间来进行对比。至于跨域的情况,可以检查一下后台的业务逻辑是否正常,而 cancel 的情况,多半是前端业务控制的,也可以看下具体的业务逻辑。
为什么 API 监控页面看到了非常多接口的 retcode 成功率都是0,或者很低?
SDK 通过从用户接口的返回值中的第一层和第二层中获取 [code, ret, retcode, errcode] 这几个参数中的任意一个,作为接口业务的返回码(区别于HTTP的状态码),默认这个返回码等于0接口为正常。
业务对于返回码有不同的定义,开发者可以通过 api 参数下的 retCodeHandler 函数对其进行矫正,retCodeHandler 函数返回 isErr 和 code 两个值。isErr 用来计算接口返回值的成功率,code 用来统计接口的返回码占比。当该函数返回 isErr 为 true 的时候,这个接口的信息会同时上报到历史日志里面的“接口返回码异常”,方便开发者定位接口问题。除此之外,还有很多非业务的接口,如一些数据上报,是不满足这些规范的,建议可以通过 beforeRequest 进行修正。
为什么接入 Aegis 后没有首屏数据?
Aegis sdk 根据 DOM 变化记录首屏,如果您的 sdk 引入较晚,或者初始化较晚,可能会出现无法获取首屏的情况。如果出现这种情况的话,建议可以试着把 sdk 引入和初始化放在更前面,如 head 里,然后再观察一下数据。
为什么有些接口的测速数据没有上报?
有可能是因为初始化 Aegis 的时候这个接口已经发出去了。Aegis web sdk 目前只劫持了 fetch 和 xhr 两种发送请求的方式,如果您的请求是其他的方式,例如 beacon,就无法监控到。Aegis 小程序 sdk 也是通过劫持 wx.request 实现的,如果在引入 Aegis 之前,wx.request 已经被修改了,也可能监控不到,建议尽早引入和初始化 Aegis sdk。
页面首屏和页面完全加载时间有什么关系?
总体来说,页面首屏和页面完全加载时间是正相关的。大多数情况下,用户的首屏时间是小于页面完全加载的。Aegis SDK 根据用户页面 DOM 变化计算首屏时间,如果用户页面完全加载后,还继续发生 DOM 变化,就有可能发生首屏时间晚于页面完全加载的情况。在服务端直出场景,瀑布图会出现首屏时间大于 dom 解析的情况,这是由于移动端设备兼容性问题,有些设备无法获取到 DNS 查询、TCP 连接、SSL 建连时间,这三个指标汇总后的平均值偏小,导致除了首屏时间外的其他指标都往左偏移。
如何获取全量上报所有接口的信息?
new Aegis({id: '',api: {reportRequest: true, // 接口全量上报,info 对全部用户生效apiDetail: true, // 上报接口的同时,也会上报接口请求参数和返回值}})
对于 SSR 页面,接入 aegis sdk 需要注意哪些问题?
接直出的页面需要注意两件事情:
1. aegis-web-sdk 只能运行在浏览器环境,所以记得在服务端不要执行初始化操作。
2. SSR 页面初始化完成比较早,所以如果把 aegis-sdk 初始化放在比较靠后的地方(body里面或者最后)可能会导致 sdk 无法获取到页面首屏的情况。建议 SSR 页面使用 script 标签引入 aegis sdk,并且放在head中初始化,解决上述两个问题。
接口名称是写在接口的参数里面的,如何进行上报?
aegis sdk 上报数据的时候,默认只上报了接口的 url,没有上报参数(aegis sdk 会默认去掉 url 中 query 的内容),对于这种情况,我们提供 reportApiSpeed.urlHandler 钩子函数对上报内容进行修正,用户可以根据 urlHandler 参数里面的内容进行优化。
例如:腾讯云控制台上的接口,名称统一都是
console.cloud.tencent.com/cgi/capi
,接口真实名称通过参数里面的 cmd 确定,这样的情况,优化方式如下:new Aegis({id: '',reportAssetSpeed: true, // 静态资源测速reportApiSpeed: {urlHandler(url) {if (url.indexOf('/cgi/capi') > -1) {const urls = url.split(/[=|&|?]/);if (urls.length > 6) {url = `${urls[0]}/${urls[6]}/${urls[2]}`;}}return url;},},});
再例如,用户的接口为 `xx.qq.com/user?id=123`,如果用户希望保留 query 中的内容,可以把 url 中的 ? 改成 #。
如果 url 中包含类似时间戳等信息,可能会导致 url 地址无限膨胀,导致数据无法聚合,因此,建议用户不要简单的替换 ?,可以使用字符串拼接把关键信息提取出来,urlHandler 中 return 的信息就是最终上报的接口 url。
new Aegis({id: '',reportAssetSpeed: true, // 静态资源测速reportApiSpeed: {urlHandler(url) {if (url.indexOf('?id=') > -1) {return url.replace('?', '#');}return url;},},});