关于如何快速定位线上异常

783 阅读4分钟

我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!

背景

作为一个前端FE开发,当产品上线后,经常会遇到各种线上问题。但是我们会经常发现,问题不能很好的复现出来,这就对我们解决问题造成相当大的困扰。而导致不能很好复现的原因,可能是网络、系统、机型或者是用户行为。所以如何让我们在面对这些问题的时候,能有个清晰的思路是必要的。

image.png

问题来源

一般情况下,我们的处理的线上问题来源主要分为两种。

  • 用户反馈
  • 系统预警

image.png

错误分类

一般情况下,面对前端问题,我们会打开我们的控制台,去检查是否有错误。

  • console
  • network

image.png

当然,这只是我们去debugger问题的方式,错误的类型主要包含了:

  • 前端代码异常
  • 请求异常
  • 静态资源异常
  • Promise异常
  • 跨域异常
  • 页面崩溃异常

image.png

异常处理

image.png

面对这些异常,我们可以通过一下的方式去捕获这些异常。

Try...Catch

可以捕获同步运行的错误,但是对语法问题和异步错误无法捕获。

使用

try {}
catch(e) {}

语法异常使用Try...Catch

image.png

异步异常使用Try...Catch

image.png

window.onerror

window.onerror是一个全局变量,默认值为null。当JS运行时发生错误时,window会触发一个ErrorEvent接口的error事件,执行window.onerror()

使用

window.onerror = function(msg, source, lineno, colno, error) {
    console.log('错误信息', msg)
    console.log('出错文件名', source)
    console.log('行号', lineno)
    console.log('列号', colno)
    console.log('Error对象', error)
}

但是,window.onerror也并不是万能的,面对JS的语法异常同样也是无法捕获的。同时在使用window.onerror的时候我们需要注意以下几个点

  • window.onerroor函数只有在返回true的时候,异常才不会向上抛出。否则运行时还是会抛出异常信息
  • onerror函数最好在所有JS脚本之前定义,否则可能存在部分异常无法捕获

window.addEventListen('error'|'unhandledrejection')

当一项资源(如图片或脚本)加载失败,加载资源的元素会触发一个 Event 接口的 error 事件,并执行该元素上的 onerror() 处理函数。这些 error 事件不会向上冒泡到 window ,不过(至少在 Firefox 中)能被单一的 window.addEventListener 捕获。

使用

window.addEventListen('error'|'unhandledrejection', e => {
    console.log(e)
})

window.onerror 和 window.addEventListen('error')的区别

window.addEventListen('error')监听js运行时错误事件,会比window.onerror先触发,与onerror的功能大体类似,不过事件回调函数传参只有一个保存所有错误信息的参数,不能阻止默认事件处理函数的执行,但可以全局捕获资源加载异常的错误

上报错误

当我们能捕获这些异常的时候,怎么去使用这些异常才能更好的协助我们去更好的、快速的处理线上问题呢?

在这里我们以Sentry为例

集成上报平台

image.png

初始化Sentry

Sentry.init({
  // 相关配置
  beforeSend(event) {
  // 在这里可根据业务情况发送特定信息
  event.info = {
    xx: 'xxx'
  };
})

配置全局Sentry

可以使用全局配置配置项目相关信息

Sentry.setUser(object);
Sentry.tags(object);
Sentry.extra(object);
Sentry.level(object);
Sentry.fingerprint(object);

// 通过 setContext,设置 key 值,可自定义随事件传递的变量名
Sentry.setContext(key, context);

标准化异常捕获

标准化上报信息,如果是请求异常捕获,可以配置request id为tag,这样,就可以通过id快速查询到sentry的信息。

Sentry.captureMessage(sentryMessage, {
  extra: {
    url,
    body: {
      code,
      message: errorMsg
    }
  },
  tags: {
    requestId: errorRes.response ? errorRes.response.requestId : ''
  }
})

集成sourceMap

将SourceMap上传到Sentry,可快速定位到源码位置

const SentryCliPlugin = require('@sentry/webpack-plugin')

module.exports = {
    configureWebpack: (config) => {
       isLive && config.plugins.push(new SentryCliPlugin({ include: './dist' }))
    },
}

代理调试

如果通过一系列操作,定位到问题归属在前端,后端数据正常。我们可以通过代理的方式在前端进行debugger调试。

工具

  • whistle
  • charles

whistle

whistle基于Node实现的跨平台web调试代理工具,类似的工具有Windows平台上的Fiddler,主要用于查看、修改HTTP、HTTPS、Websocket的请求、响应,也可以作为HTTP代理服务器使用,不同于Fiddler通过断点修改请求响应的方式,whistle采用的是类似配置系统hosts的方式,一切操作都可以通过配置实现,支持域名、路径、正则表达式、通配符、通配路径等多种匹配方式

charles

Charles 是一个 HTTP 代理 / HTTP 监视器 / 反向代理,它使开发人员能够查看他们的机器和 Internet 之间的所有 HTTP 和 SSL / HTTPS 流量。这包括请求、响应和 HTTP 标头(其中包含 cookie 和缓存信息)。官方地址:www.charlesproxy.com/

使用

# 域名匹配
 www.example.com
 # 带端口的域名
 www.example.com:6666
 # 带协议的域名,支持:http、https、ws、wss、tunnel
 http://www.example.com

 # 路径匹配,同样支持带协议、端口
 www.example.com/test
 https:/www.exapmle.com/test
 https:/www.exapmle.com:6666/test

 # 正则匹配
 /^https?://www.example.com/test/(.*)/ referer://http://www.test.com/$1

 # 通配符匹配
 ^www.example.com/test/*** referer://http://www.test.com/$1

这样,我们可以将线上的地址代理到本地服务,然后通过线上数据去复现问题。去解决问题

结束语

2022.02.23

木更