UNPKG

vue-exception-captor

Version:

用于捕获Vue前端工程中的全局异常、Promise异常,并支持HTTP模式上报到后台存储

179 lines (163 loc) 5.78 kB
/* * @Author: CaoZhongQian * @Date: 2023-01-27 22:11:21 * @LastEditors: CaoZhongQian * @LastEditTime: 2023-01-31 16:35:05 * @FilePath: \vue-exception-captor\src\index.js * @Description: 全局异常捕获插件 */ // Vue组件内的同步异常,无法被window.onerror捕获 // Vue组件内部的定时器异常,可以被window.onerror捕获 // window.onerror不能捕获promise异常 (function() { Number.isInteger = Number.isInteger || function(value) { return typeof value === 'number' && isFinite(value) && Math.floor(value) === value } var Axios = require('axios') var VueExceptionCaptor = { // 产品名字 productName: 'unknown', // 用户名称 username: 'unknown', // 上报到后台存储的Http接口地址 reportUrl: '', // axios http客户端 reportClient: null, // 是否禁用上报 disabled: false, // 是否启用控制台打印 console: false, install: function(Vue, options) { this.productName = options.productName || this.productName this.username = options.username || this.username this.reportUrl = options.reportUrl || '' this.disabled = options.disabled || false this.console = options.console || false this.reportClient = Axios.create({ baseURL: this.reportUrl, withCredentials: false, timeout: 3000 }) window.onerror = (event, source, lineNo, columnNo, error) => { if (this.console) { console.log('进入了window.onerror') console.log(error) } if (!this.disabled) { this.reportException('window.onerror', error, '捕获全局异常', 'error') } return true } window.onunhandledrejection = (event) => { if (this.console) { console.log('进入了window.onunhandledrejection') console.log(event) } if (!this.disabled) { this.reportException('window.onunhandledrejection', event.reason, '捕获全局Promise异常', 'error') } } Vue.config.errorHandler = (error, vm, info) => { if (this.console) { console.log('进入了Vue.config.errorHandler') console.log(error) } if (!this.disabled) { this.reportException('vue.errorHandler', error, '捕获Vue全局异常', 'error') } } Vue.prototype.$exceptionCaptor = this Vue.prototype.$reportException = this.reportException }, /** * @description: 上报异常 * @param {*} type vue.errorHandler、window.onunhandledrejection、window.onunhandledrejection * @param {*} error 异常信息 * @param {*} message 说明信息 * @param {*} level 异常等级,默认为error * @return {*} */ async reportException(type, error, message, level = 'error') { try { const exception = this.getException(type, error, message, level) await this.report(exception) } catch (error) { console.log('处理上报的异常出错') console.log(error) } }, /** * @description: 生成上报的异常数据 * @param {*} type type vue.errorHandler、window.onunhandledrejection、window.onunhandledrejection * @param {*} error 异常信息 * @param {*} message 说明信息 * @param {*} level 异常等级,默认为error * @return {*} */ getException(type, error, message, level = 'error') { const jsonError = this.serializeError(error) return { product: this.productName, username: this.username, href: window.location.href, type: type, level: level, message: message || '', error: jsonError } }, /** * @description: 序列化Error对象 * @param {*} error * @return {*} */ serializeError(error) { try { return error ? JSON.stringify(error, Object.getOwnPropertyNames(error), null) : '' } catch (error) { return '' } }, /** * @description: 上报异常到后台服务 * @param {*} exception * @return {*} */ async report(exception) { try { // 将异常序列化单行字符串,保证body体的json到了nginx是单行的json内容,解决filebeat解析多行文本失败的BUG const exceptionStr = JSON.stringify(exception) await this.reportClient({ method: 'post', data: exceptionStr, headers: { 'Content-Type': 'application/json' } }) } catch (error) { console.log('上报全局异常出错') console.log(error) } }, /** * @description: 设置上报的用户信息,用于标识异常信息来自哪个用户 * @param {*} username * @return {*} */ setExceptionUserName(username) { this.username = username } } if (typeof exports === 'object') { module.exports = VueExceptionCaptor } else if (typeof define === 'function' && define.amd) { define([], function() { return VueExceptionCaptor }) } else if (window.Vue) { window.VueExceptionCaptor = VueExceptionCaptor Vue.use(VueExceptionCaptor) } })()