脚本错误量极致优化:监控上报与 Script error

原文地址

在前端开发工作中,除了项目开发保质保量上线以外,项目的数据监控也应该配套起来,确保线上的正常运转。如上报 pv 监控项目是否正常运转;测速上报反应项目质量;脚本错误监控作为监控中重要一环,当页面发生报错的时候,通过上报错误信息,能及时发现存在问题,修复优化、减少损失。

本文基于在手 Q 家校群前端脚本错误量优化的方案,致力于打造极致的脚本错误优化。

监控上报

脚本错误主要有两类:语法错误、运行时错误。

监控的方式主要有两种:try-catch、window.onerror。

监控方式

示例 · try-catch

try {
test // <- throw error
} catch(e){
console.log('运行时错误信息 ↙');
console.log(e);
}

通过给代码块进行 try-catch 包装,当代码块出错时 catch 将能捕获到错误信息,页面也将继续执行。

当发生语法错误或异步错误时,则无法正常捕捉。

示例 · try-catch (语法报错)

try {
function empty() // <- throw error 语法错误
} catch(e){
console.log('语法错误信息 ↙');
console.log(e);
}

无法捕捉错误

示例 · try-catch (异步错误)

try {
setTimeout(function() {
test // <- throw error 异步错误
},0)
} catch(e){
console.log('异步错误信息 ↙');
console.log(e);
}

无法捕捉错误

语法错误无法在 try-catch 中进行捕抓、而异步报错则可以通过为异步函数块再包装一层 try-catch,增加标识信息来配合定位,可以用工具来进行处理,这里不展开。

示例 · window.onerror

/**
* @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('onerror 错误信息 ↙');
console.log({
msg, url, row, col, error
})
};

test // <- throw error

window.onerror 能捕捉到当前页面的语法错误或运行时报错,是十分强大的。

那么 try-catch 是否不再需要呢?其实并不是。

在使用过程中的体会:onerror 主要用来捕获预料之外的错误,而 try-catch 则可以用在预知情况下监控特定错误,两种形式结合使用更加高效。

上报方式

监控错误拿到了报错信息,接下来则是将捕抓的错误信息发送到信息收集平台上,发送的形式主要有两种:

  1. 通过 Ajax 发送数据
  2. 动态创建 img 标签的形式

示例 · 动态创建 img 标签进行上报

function report(msg, level) {
var reportUrl = "http://localhost:8055/report";
new Image().src = reportUrl + '?msg=' + msg;
}

监控上报整体流程

监控报错,并将捕捉到的错误信息上报给数据收集平台,如下图

错误信息分析 · Script error

有了监控了后,就可以在收集平台上进行查看脚本错误量的日志统计。

发现占据榜首的错误信息 “Script error.” 具有非常高的比例,没有无具体的错误信息,无法定位问题,而这是怎么产生的呢?

产生 Script error 的原因

翻看在 webkit 的源码可以看到 “Script error.” 是浏览器在同源策略限制下所产生的。浏览器出于安全上的考虑,当页面引用的非同域的外部脚本中抛出了异常,此时本页面无权限获得这个异常详情, 将输出 Script error 的错误信息。

优化 Script error

Script error 来自同源策略的影响,那么解决的方案之一是进行资源的同源化,另外也可以利用跨源资源共享机制( CORS )。

方案一:同源化

  1. 将 js 代码内联到 html 文件中
  2. 将 js 文件与 html 文件放到同一域名下

以上两种方式能够简单直接地解决问题,但也可能带来其他影响,如内联资源不好利用文件缓存,同域无法充分利用 cdn 优势等等。

方案二:跨源资源共享机制( CORS )

跨源资源共享 ( CORS ) 机制让 Web 应用服务器能支持跨站访问控制,从而能够安全地跨站数据传输。主要是通过给请求带上特定头信息,服务器实现了 CORS 接口,就可以跨源通信,从而能够看到具体报错信息。

1. 为页面上 script 标签添加 crossorigin 属性。

<script src="http://127.0.0.1:8077/main.js" crossorigin></script>

增加 crossorigin 属性后,浏览器将自动在请求头中添加一个 Origin 字段,发起一个 跨来源资源共享 请求。Origin 向服务端表明了请求来源,服务端将根据来源判断是否正常响应。

2. 响应头中增加 Access-Control-Allow-Origin 来支持跨域资源共享。

Access-Control-Allow-Origin: * 表示通过该跨域请求,且该资源可以被任意站点跨站访问。而当该资源仅允许来自 http://127.0.0.1:8066 的跨站请求,其它站点都不能跨站访问时,将可以返回:

Access-Control-Allow-Origin:http://127.0.0.1:8066

3. 指定域名的 Access-Control-Allow-Origin 的响应头中需带上 Vary:Origin。

Vary 字段的作用在于为缓存服务器提供缓存规则及缓存筛选的依据。当增加 Vary:Origin 响应头后,缓存服务器将会按照 Origin 字段的内容,缓存不同版本,在请求响应时根据请求头中的 Origin 决定是否能够使用缓存响应。

举例 · 不加 Vary 将存在错误命中缓存的问题

上图中,第一个请求(Origin: 127.0.0.1:8066)响应被浏览器缓存了,当第二个请求(Origin: 127.0.0.1:8888)发起,被错误命中了前一个请求的缓存,收到了 Access-Control-Allow-Origin:http://127.0.0.1:8066 的响应时,将导致资源加载失败。

所以当 Access-Control-Allow-Origin 不是返回为 * 时,需要加上 Vary 返回头来避免引缓存导致的权限问题。

跨域脚本报错产生 Script error. 通过以上方式进行处理后将能够捕获到具体的报错信息了。在 NodeJS 的实现中主要通过添加以下代码:

app.use(function *(next){
// 拿到请求头中的 Origin
var requestOrigin = this.get('Origin'); 
if (!requestOrigin) { // 不存在则忽略
return yield next;
}

// 设置 Access-Control-Allow-Origin: Origin
this.set('Access-Control-Allow-Origin', requestOrigin);

// 设置 Vary: Origin
this.vary('Origin');
return yield next;
});

以上为本文所有内容,兄弟篇:脚本错误量极致优化-让脚本错误一目了然

查看更多文章: https://github.com/joeyguo/blog

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

郭林烁的专栏

1 篇文章1 人订阅

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏网络

一步步带你了解前后端分离利器之JWT

一、HTTP的无状态性 HTTP 是无状态协议,它不对之前发送过的请求和响应的状态进行管理。也就是说,无法根据之前的状态进行本次的请求处理。假设要求登录认证的 ...

2365
来自专栏康怀帅的专栏

macOS 对 gdb 进行代码签名

在 macOS 使用 GDB 调试 C 语言代码,必须对 gdb 进行代码签名,否则 GDB 不能运行! 创建证书 钥匙串访问 打开菜单:钥匙串访问-》证书助理...

2704
来自专栏進无尽的文章

精析-苹果开发者证书的实现机制

      在iOS开发过程中,不可避免的要和证书打交道,真机调试、App上架、打包给测试去测试等都需要搞证书。在此过程中我们会遇到很多的问题,但是如果掌握了真...

912
来自专栏大宽宽的碎碎念

实现一个靠谱的Web认证两种认证JWT怎么存储认证信息防止CSRF总是使用https认证信息不应该永久有效总结一下

38710
来自专栏服务端思维

跨域问题,解决之道

跨域问题,是由于JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。换句话说,只有JavaScript存在跨域问题。

691
来自专栏程序猿DD

八幅漫画理解使用 JWT 设计的单点登录系统

上次在《JSON Web Token - 在Web应用间安全地传递信息》中我提到了JSON Web Token可以用来设计单点登录系统。我尝试用八幅漫画先让大家...

873
来自专栏程序猿DD

Spring Cloud构建微服务架构:分布式配置中心(加密解密)

最近正好想发一篇关于配置中心加密的细节内容,结果发现基础的加密解密居然漏了,所以在这个入门系列中补充一下。后面再更新一下,使用配置中心的一些经验和教训。 ? 在...

3207
来自专栏魏艾斯博客www.vpsss.net

补充记录腾讯云 DNSPod 域名 API 申请 Let’s Encrypt 泛域名 SSL 证书需要注意的几点

刚写完了腾讯云 DNSPod 域名 API 申请 Let’s Encrypt 泛域名 SSL 证书这篇教程,感觉中间有几点是新手需要注意的,申请 SSL 泛域名...

4954
来自专栏腾讯AlloyTeam的专栏

脚本错误量极致优化-监控上报与 Script error

在前端开发工作中,除了项目开发保质保量上线以外,项目的数据监控也应该配套起来,确保线上的正常运转。如上报 pv 监控项目是否正常运转;测速上报反应项目质量。

1520
来自专栏Web项目聚集地

什么是跨域?解决方案有哪些?

同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同...

1002

扫码关注云+社区