- 静态资源加载异常
静态资源加载失败,可以通过window的error事件进行捕获。核心代码
// 全局监控资源加载错误 window.addEventListener( 'error', (event) => { // 过滤 js error const target = event.target || event.srcElement; const isElementTarget = target instanceof HTMLScriptElement || target instanceof HTMLLinkElement || target instanceof HTMLImageElement; if (!isElementTarget) { return false; } // 上报资源地址 const url = (target as HTMLScriptElement | HTMLImageElement).src || (target as HTMLLinkElement).href; this.log({ error: new Error(`ResourceLoadError: ${url}`), type: 'resource load' }); }, true );
- 接口异常(后端和 native 的接口)
可以通过在封装的 http 模块中,全局集成上报错误函数(native 接口的错误上报类似,可在项目中查看)。核心代码如下:
function errorReport( url: string, error: string | Error, requestOptions: AxiosRequestConfig, response?: AnyObject ) { if (window.$sentry) { const errorInfo: RequestErrorInfo = { error: typeof error === 'string' ? new Error(error) : error, type: 'request', requestUrl: url, requestOptions: JSON.stringify(requestOptions) }; if (response) { errorInfo.response = JSON.stringify(response); } window.$sentry.log(errorInfo); } }
- js 报错
关于全局 js 报错,sentry 针对的前端的 sdk 已经通过 window.onerror 和 window.addEventListener('unhandledrejection', ..., false) 进行全局监听并上报。
需要注意的是其中 window.onerror = (message, source, lineno, colno, error) =>{} 不同于 window.addEventListener('error', ...),window.onerror 捕获的信息更丰富,包括了错误字符串信息、发生错误的 js 文件,错误所在的行数、列数、和 Error 对象(其中还会有调用堆栈信息等)。所以 sentry 会选择 window.onerror 进行 js 全局监控。
但有一种错误是 window.onerror 监听不到的,那就是 unhandledrejection 错误,这个错误是当 promise reject 后没有 catch 住所引起的。当然 sentry 的 sdk 也已经做了监听。
针对 vue 项目,也可对 errorHandler 钩子进行全局监听,react 的话可以通过 componentDidCatch 钩子,vue 相关代码如下:
// 全局监控 Vue errorHandler Vue.config.errorHandler = (error, vm, info) => { window.$sentry.log({ error, type: 'vue errorHandler', vm, info }); };
- 网页崩溃
为部署到线上的代码一般都是经过压缩混淆的,如果没有上传 sourcemap 的话,是无法定位到具体源码的,可以现在 项目中添加 .sentryclirc 文件,其中内容可参考本项目的 .sentryclirc,然后通过 sentry-cli (需要全局全装 sentry-cli 即npm install sentry-cli)命令行工具进行上传,命令如下:
sentry-cli releases -o 机构名 -p 项目名 files 版本 upload-sourcemaps sourcemap 文件相对位置 --url-prefix js 在线上相对根目录的位置 --rewrite // 示例 sentry-cli releases -o mcukingdom -p hello-world files 0.2.1 upload-sourcemaps dist/js --url-prefix '~/js/' --rewrite
官方也提供了 webpack 插件 sentry-webpack-plugin,当打包时触发 webpack 的 after-emit 事件钩子(即生成资源到 output 目录之后),插件会自动上传打包目录中的 sourcemap 和关联的 js,vue.config.js相关配置:
const path = require('path'); const webpack = require('webpack'); const SentryPlugin = require('@sentry/webpack-plugin'); const LodashModuleReplacementPlugin = require('lodash-webpack-plugin'); const IS_PRO = NODE_ENV === 'production'; const commonPlugins = [ new webpack.DefinePlugin({ __VERSION__: JSON.stringify(version) }) ]; module.exports = { ... configureWebpack: () => { if (IS_PRO) { const productionPlugins = [new LodashModuleReplacementPlugin()]; productionPlugins.push( new SentryPlugin({ release: version, //发布的版本 include: path.join(__dirname, './dist/js'), //需要上传到sentry服务器的资源目录,会自动匹配 js 以及 map 文件 urlPrefix: '~/mobile-web-best-practice/js', //线上对应的 url 资源的相对路径 ignore: ['node_modules'] //忽略文件目录, 当然我们在 inlcude 中制定了文件路径,这个忽略目录可以不加 }) ); return { plugins: [...commonPlugins, ...productionPlugins], externals: { // key 是给 import 的时候用的,value 表示的是如何在 global 中访问到该对象 vue: 'Vue', vuex: 'Vuex', 'vue-router': 'VueRouter' } }; } else { return { plugins: [...commonPlugins] }; } } ... }
通常为了安全,是不允许在线上部署 sourcemap 文件的,所以上传 sourcemap 到 sentry 后,可手动删除线上 sourcemap 文件。