首页 > 其他分享 >vue语法错误 + Promise错误 + js 错误,通过钉钉报警

vue语法错误 + Promise错误 + js 错误,通过钉钉报警

时间:2023-08-14 17:56:24浏览次数:45  
标签:vue return 错误 语法错误 -- window var navigator

 

 

一、背景:

为了使系统更加稳定,在用户使用期间,若发现异常,可及时应对,采取了“报警机制”。

通常“报警机制”分为2种,一种是后端对api监控及自定义监控,出现异常,通过钉钉或邮件的形式通知,第二种是前端对js语法,vue语法,自定义报错进行监控,以此来规范代码质量,保证系统预警

二、流程步骤

1. 收集错误(错误类型包含 vue错误 + js 错误 + Promise 错误 + 自定义错误)

2. 关联钉钉

3. 错误信息发送

三、前期准备内容

1. 钉钉软件,自定义机器人接入,文档链接

2. 签名计算(前后端联调,统一加密方式)

四、参考代码

1. 收集错误阶段(main.js)

 1 import { createApp } from 'vue'
 2 import { errorHandler, detectOS, digits, getBrowserInfo, format } from '@/assets/scripts/errorPlugin' // 收集错误信息
 3 
 4 const app = createApp(App)
 5 // 1. 用于组件生命周期中的错误、自定义事件处理函数内部错误、v-on DOM 监听器内部抛出的错误、处理返回 Promise 链的错误
 6 app.config.errorHandler = errorHandler
 7 // 2. 处理 JS 的额外错误
 8 // eslint-disable-next-line max-params
 9 window.onerror = function (message, source, line, column, error) {
10     // 了解文档: https://juejin.cn/post/6844904093979246606
11     if (message === 'ResizeObserver loop limit exceeded') {
12         console.warn('Ignored: ResizeObserver loop limit exceeded')
13         return false
14     }
15     if (message == 'cancel') return false
16     let errMsg = null
17     if (message == 'Script error.') {
18         // 跨域
19         errMsg = `
20         --infoType: JS 无法访问, 请在控制台查看具体错误
21         --apName : 用户端-${process.env.NODE_ENV === 'development' ? '测试环境' : '生产环境'}
22         --url: ${window.location.href}
23         --browser:${detectOS()}-${digits()} ${getBrowserInfo()}
24         --time: ${format('yyyy-MM-dd hh:mm:ss')}
25         --userInfo: ${sessionStorage.getItem('AI_INFO')}
26         --info: 浏览器跨域请求一个脚本执行出错
27         `
28         return false
29     }
30     // ------排除这两个文件错误信息的检查开始-----
31     let noNeedFile = ['app', 'contextMenuFilter']
32     let noContinue = false
33     noNeedFile.map((res) => {
34         if (source.indexOf(res) != -1) noContinue = true
35     })
36     console.log('排除文件了')
37     if (noContinue) return false
38     console.log('没排除文件')
39     // ------排除这两个文件错误信息的检查结束-----
40     errMsg = `
41         --infoType: JS 错误
42         --apName : 用户端-${process.env.NODE_ENV === 'development' ? '测试环境' : '生产环境'}
43         --url: ${window.location.href}
44         --browser:${detectOS()}-${digits()} ${getBrowserInfo()}
45         --time: ${format('yyyy-MM-dd hh:mm:ss')}
46         --userInfo: ${sessionStorage.getItem('AI_INFO')}
47         --info: ${message}-${source}-${JSON.stringify(error)}
48         `
49     errorHandler(errMsg, null, 'JS错误')
50 }
51 // 3. 处理 Promise 错误
52 window.addEventListener('unhandledrejection', (event) => {
53     console.log('event', event.reason)
54     // 全局存在的未处理的 Promise 异常,比如: Promise.reject()
55     // 场景: 接口异常
56     if (event.reason == 'cancel') return false
57     let errMsg = `
58     --infoType: 捕获Promise异常
59     --apName : 用户端-${process.env.NODE_ENV === 'development' ? '测试环境' : '生产环境'}
60     --url: ${window.location.href}
61     --browser:${detectOS()}-${digits()} ${getBrowserInfo()}
62     --time: ${format('yyyy-MM-dd hh:mm:ss')}
63     --userInfo: ${sessionStorage.getItem('AI_INFO')}
64     --errorInfo: ${JSON.stringify(event.reason)}
65     `
66 
67     errorHandler(errMsg, null, 'Promise错误')
68 })
69 app.mount('#app')
View Code

2. 关联钉钉(src\assets\scripts\robot.js)

View Code

3. 发送错误信息到钉钉软件(src\assets\scripts\errorPlugin.js) 

import ChatBot from './robot.js'

export const errorHandler = (err, vm, info) => {
    let token = sessionStorage.getItem('AI_TOKEN') || null
    if (!token) return
    let errInfo = null
    if (info !== 'JS错误' || info !== 'Promise错误') {
        errInfo = `
        --infoType: vue异常错误
        --apName : 用户端-${process.env.NODE_ENV === 'development' ? '测试环境' : '生产环境'}
        --url: ${window.location.href}
        --browser:${detectOS()}-${digits()} ${getBrowserInfo()}
        --time: ${format('yyyy-MM-dd hh:mm:ss')}
        --userInfo: ${sessionStorage.getItem('AI_INFO')}
        --errorInfo: ${err}-${JSON.stringify(info)}
        `
    } else {
        errInfo = err
    }
    // 将捕获的错误, 通过钉钉报警
    robotDD(errInfo)
}

const robotDD = (errMsg) => {
    const robot = new ChatBot({
        webhook: 'https://oapi.dingtalk.com/robot/send?access_token=***',
        secret: '***'
    })
    // 规定发送的消息的类型和参数
    let textContent = {
        msgtype: 'text',
        text: {
            content: errMsg // 注意了,字符串里面的错误汉字,其实就是你在钉钉报警设置的自定义字段,两个地方需要相同,否则不会发送到群里
        }
    }
    // 机器人发送消息
    robot
        .send(textContent)
        .then((res) => {
            console.error(res)
        })
        .catch(() => {
            console.log('钉钉报警错误')
            // ElMessage.error({
            //     message: `钉钉报警错误`
            // })
        })
}
export const format = (fmt) => {
    //author: meizz
    var o = {
        'M+': new Date().getMonth() + 1, //月份
        'd+': new Date().getDate(), //日
        'h+': new Date().getHours(), //小时
        'm+': new Date().getMinutes(), //分
        's+': new Date().getSeconds(), //秒
        'q+': Math.floor((new Date().getMonth() + 3) / 3), //季度
        S: new Date().getMilliseconds() //毫秒
    }

    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (new Date().getFullYear() + '').substr(4 - RegExp.$1.length))
    for (var k in o) if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length))
    return fmt
}

/**
 * 初始化设备信息
 */
export const initDeviceInfo = () => {
    let _deviceInfo = '' //设备信息
    console.log(navigator, 'navigator')
    if (navigator == null) {
        _deviceInfo = 'PC'
    }
    if (navigator.userAgent != null) {
        var su = navigator.userAgent.toLowerCase(),
            mb = ['ipad', 'iphone os', 'midp', 'rv:1.2.3.4', 'ucweb', 'android', 'windows ce', 'windows mobile']
        // 开始遍历提前设定好的设备关键字,如果设备信息中包含关键字,则说明是该设备
        for (var i in mb) {
            if (su.indexOf(mb[i]) > 0) {
                _deviceInfo = mb[i]
                break
            }
        }
    }
    return _deviceInfo
}

/**
 * 获取浏览器的信息
 */

export const getBrowserInfo = () => {
    var output = 'other'
    // Opera 8.0+
    var isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0
    if (isOpera) {
        output = 'Opera'
    }
    // Firefox 1.0+
    var isFirefox = typeof InstallTrigger !== 'undefined'
    if (isFirefox) {
        output = 'Firefox'
    }
    // Safari 3.0+ "[object HTMLElementConstructor]"
    var isSafari =
        /constructor/i.test(window.HTMLElement) ||
        (function (p) {
            return p.toString() === '[object SafariRemoteNotification]'
        })(!window['safari'] || (typeof safari !== 'undefined' && safari.pushNotification))
    if (isSafari) {
        output = 'Safari'
    }
    // Internet Explorer 6-11
    var isIE = /*@cc_on!@*/ false || !!document.documentMode
    if (isIE) {
        output = 'IE'
    }
    // Edge 20+
    var isEdge = !isIE && !!window.StyleMedia
    if (isEdge) {
        output = 'Edge'
    }
    // Chrome 1 - 79
    var isChrome = !!window.chrome && navigator.userAgent.indexOf('Chrome') !== -1
    if (isChrome) {
        output = 'Chrome'
    }
    // Edge (based on chromium) detection
    var isEdgeChromium = isChrome && navigator.userAgent.indexOf('Edg') !== -1
    if (isEdgeChromium) {
        output = 'EdgeChromium'
    }
    return output
}

export const detectOS = () => {
    var userAgent = window.navigator.userAgent,
        platform = window.navigator.platform,
        macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'],
        windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'],
        iosPlatforms = ['iPhone', 'iPad', 'iPod'],
        os = null

    if (macosPlatforms.indexOf(platform) !== -1) {
        os = 'Mac OS'
    } else if (iosPlatforms.indexOf(platform) !== -1) {
        os = 'iOS'
    } else if (windowsPlatforms.indexOf(platform) !== -1) {
        os = 'Windows'
    } else if (/Android/.test(userAgent)) {
        os = 'Android'
    } else if (!os && /Linux/.test(platform)) {
        os = 'Linux'
    }
    return os
}

export const digits = () => {
    var sUserAgent = navigator.userAgent
    var is64 = sUserAgent.indexOf('WOW64') > -1
    if (is64) {
        return '64bit'
    } else {
        return '32bit'
    }
}
View Code

 五、最终实现效果

 

标签:vue,return,错误,语法错误,--,window,var,navigator
From: https://www.cnblogs.com/gqx-html/p/17629344.html

相关文章

  • vue.use()详解
    原文链接:https://blog.csdn.net/sunyctf/article/details/127706967官网解释:前言:相信很多人在用Vue使用别人的组件时,会在在main.js中用到Vue.use(xx)。例如:Vue.use(VueRouter)、Vue.use(MintUI)、Vue.use(ElementUI)。但是用axios时,就不需要用Vue.use(axios),就......
  • vue-router动态路由无限循环
    //isLogined用来判断用户是否已登录router.beforeEach((to,from,next)=>{if(isLogined){next()}else{console.log('测试')next('login')}})next()表示放行,直接进入to路由,不会再次调用router.beforeEach()next(path:...to,replace:true)拦截......
  • Vue3 中的v-model实现父子组件数据同步通信
    v-model在vue2中也就是双向绑定作用,但是在vue3中除了实现双向绑定外,还可以进行组件的通信父子组件的数据同步,接下来看看例子:<template><h1>{{num}}</h1><child-eventv-model="num"></child-event></template><scriptlang="ts"setup......
  • vue中使用sockjs
    1,安装依赖npminstallsockjs-client--savenpminstall stompjs--save2,使用混入封装在src下创建mixins文件夹,然后创建sockjs.js文件importSockJSfrom"sockjs-client";importStompfrom"stompjs";exportconstsockjsMixins={data(){return{......
  • vue——qq音乐播放器(1) 左边导航栏样式的实现
    实现结果:左侧导航栏样式实现完整代码:1<template>2<!--左边导航条-->3<divclass="leftnav">4<!--logo-->5<divclass="logo"></div>6<divclass="my-scroll">7......
  • 如何在本地给 vue-router4 扩展功能?
    背景前段时间给基于vue3的H5项目做一些优化,该项目经常会有一些页面间的通信,譬如选择地址、乘机人等信息后回填到上一个页面。对于这种简单、频繁的通信,实在不想搞成重火力(eg:pinia)。最好让使用者用完即走,不用操心除业务逻辑之外的任何事情。路由控制页面通信既然是页面间的......
  • 记录一次错误
    记录一次错误需求:输出一个爱心****** ********* ******* ***** *** *publicclassForExer{ publicstaticvoidmain(String[]args){ for(inti=6;i>=1;i--){ for(intk=1;k<=6-i;k++){ System.out.print(&quo......
  • [完结8章]程序员的 AI 启蒙课,ChatGPT 辅助开发 Vue3 项目
    点击下载:程序员的AI启蒙课:ChatGPT让你1人顶3人提取码:8zwd Vue是一款用于构建用户界面的JavaScript框,它基于标准的HTML、CSS和JavaScript构建,并提供了一套声明式的、组件化的编程模型,用以帮助开发者高效地开发用户界面。目前,Vue3.0正式版也发布了两年的时间,越......
  • vue3+typescript中的props
     以上是子组件 以上是父组件<scriptsetuplangs="ts">letprops=defineProps(['info','money'])//父子组件的通信需要用到defineProps方法去接受父组件想要传递的数据console.info(props)</script>需要注意的就是:props可以实现父子组件的通信,但是props的......
  • vue2和vue3中插槽写法区别
    一、slot是什么在HTML中slot元素,作为WebComponents技术套件的一部分,是Web组件内的一个占位符。该占位符可以在后期使用自己的标记语言填充。(我们可以理解为solt在组件模板中占好了位置,当使用该组件标签时候,组件标签里面的内容就会自动填坑(替换组件模板中slot位置),作为承......