侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

JS错误处理:前端JS/Vue/React/Iframe/跨域/Node

前端  /  管理员 发布于 6年前   447

js错误捕获

js错误的实质,也是发出一个事件,处理他

error实例对象

对象属性

message:错误提示信息
name:错误名称(非标准属性)宿主环境赋予
stack:错误的堆栈(非标准属性)宿主环境赋予

对象类型(7种)

SyntaxError对象是解析代码时发生的语法错误
ReferenceError对象是引用一个不存在的变量时发生的错误
RangeError对象是一个值超出有效范围时发生的错误(一是数组长度为负数,二是Number对象的方法参数超出范围,以及函数堆栈超过最大值)
TypeError对象是变量或参数不是预期类型时发生的错误:对字符串、布尔值、数值等原始类型的值使用new命令
URIError对象是 URI 相关函数的参数不正确时抛出的错误:使用函数不当
eval函数没有被正确执行时,会抛出EvalError错误 - 不再使用,为了代码兼容

自定义错误

function UserError(message) {  this.message = message || '默认信息';  this.name = 'UserError';}UserError.prototype = new Error();UserError.prototype.constructor = UserError;new UserError('这是自定义的错误!');


Js运行时错误处理机制

try..catch…finally

范围:用来捕获任何类型的同步错误,可以捕获async / await的代码,但无法捕获promise、setTimeout、dom回调(eg:onclick点击回调)的代码,在回调函数里面写try…catch可以捕获,但包在外面不会捕获,无法捕获语法错误

异步不捕获原因:

async/await捕获原因:window.onerror

范围:同步错误和异步错误都可以捕获,但无法捕获到静态资源异常,或者接口异常(网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行),无法捕获语法错误

原理:当 JS 运行时错误发生时,window 会触发一个 ErrorEvent 接口的 error 事件

参数

/*** @param {String}  message    错误信息* @param {String}  source    出错文件* @param {Number}  lineno    行号* @param {Number}  colno    列号

*/window.onerror = function(message, source, lineno, colno, error) {   console.log('捕获到异常:',{message, source, lineno, colno, error});}```

补充:window.onerror 函数只有在返回 true 的时候,异常才不会向上抛出,否则即使是知道异常的发生控制台还是会显示 Uncaught Error: xxxxx

onerror 最好写在所有 JS 脚本的前面,否则有可能捕获不到错误;(捕获的是全局错误)


资源加载错误

window.addEventListener(一项资源(如图片或脚本)加载失败,加载资源的元素会触发一个 Event 接口的 error事件,并执行该元素上的onerror() 处理函数,有浏览器兼容问题)

注意:只能捕获无法冒泡

window.addEventListener('error', (error) => {    console.log('捕获到异常:', error);}, true) // 一定要加true,捕获但不冒泡

Script error跨域的静态资源加载异常捕获(cdn文件等)

跨域文件只会报Script error,没有详细信息,怎么解决:

客户端:script标签添加crossOrigin

服务端:设置:Access-Control-Allow-Origin

<script src="http://jartto.wang/main.js" crossorigin></script>


iframe异常

使用window.onerror

<iframe src="http://www.fly63.com/article/detial/3373/./iframe.html" frameborder="0"></iframe><script>  window.frames[0].onerror = function (message, source, lineno, colno, error) {    console.log('捕获到 iframe 异常:',{message, source, lineno, colno, error});    return true;  };</script>


promise异常捕获

没有写 catch 的 Promise 中抛出的错误无法被 onerror 或 try-catch 捕获到

为了防止有漏掉的 Promise 异常,建议在全局增加一个对 unhandledrejection 的监听,用来全局监听Uncaught Promise Error

window.addEventListener("unhandledrejection", function(e){  console.log(e);});

补充:如果去掉控制台的异常显示,需要加上:event.preventDefault();


vue异常捕获

vue errorHandler

Vue.config.errorHandler = (err, vm, info) => {  console.error('通过vue errorHandler捕获的错误');  console.error(err);  console.error(vm);  console.error(info);}


react异常捕获

componentDidCatch(react16)

新概念Error boundary(React16):UI的某部分引起的 JS 错误不会破坏整个程序(只有 class component可以成为一个 error boundaries)

不会捕获以下错误

1.事件处理器2.异步代码3.服务端的渲染代码4.在 error boundaries 区域内的错误

Eg: 全局一个error boundary 组件就够用啦

class ErrorBoundary extends React.Component {  constructor(props) {    super(props);    this.state = { hasError: false };  }   componentDidCatch(error, info) {    // Display fallback UI    this.setState({ hasError: true });    // You can also log the error to an error reporting service    logErrorToMyService(error, info);  }   render() {    if (this.state.hasError) {      // You can render any custom fallback UI      return <h1>Something went wrong.</h1>;    }    return this.props.children;  }}<ErrorBoundary>  <MyWidget /></ErrorBoundary>


页面崩溃和卡顿处理

卡顿:网页暂时响应比较慢, JS 可能无法及时执行

解决:window 对象的 load 和 beforeunload 事件实现了网页崩溃的监控

window.addEventListener('load', function () {    sessionStorage.setItem('good_exit', 'pending');    setInterval(function () {        sessionStorage.setItem('time_before_crash', new Date().toString());    }, 1000);  });  window.addEventListener('beforeunload', function () {    sessionStorage.setItem('good_exit', 'true');  });  if(sessionStorage.getItem('good_exit') &&    sessionStorage.getItem('good_exit') !== 'true') {    /*        insert crash logging code here    */    alert('Hey, welcome back from your crash, looks like you crashed on: ' + sessionStorage.getItem('time_before_crash'));  }

崩溃:JS 都不运行了,还有什么办法可以监控网页的崩溃,并将网页崩溃上报呢

解决:Service Worker 来实现网页崩溃的监控

Service Worker 有自己独立的工作线程,与网页区分开,网页崩溃了,Service Worker一般情况下不会崩溃;

Service Worker 生命周期一般要比网页还要长,可以用来监控网页的状态;

网页可以通过 navigator.serviceWorker.controller.postMessage API 向掌管自己的 SW发送消息。


错误上报机制

Ajax 发送数据
因为 Ajax 请求本身也有可能会发生异常,而且有可能会引发跨域问题,一般情况下更推荐使用动态创建 img 标签的形式进行上报。

动态创建 img 标签的形式 更常用,简单,无跨越问题

function report(error) {  let reportUrl = 'http://jartto.wang/report';  new Image().src = `${reportUrl}?logs=${error}`;}

如果你的网站访问量很大,那么一个必然的错误发送的信息就有很多条,这时候,我们需要设置采集率,从而减缓服务器的压力:

Reporter.send = function(data) {  // 只采集 30%  if(Math.random() < 0.3) {    send(data)      // 上报错误信息  }}
js源代码压缩如何定位:成熟方案提供sentry

sentry 是一个实时的错误日志追踪和聚合平台,包含了上面 sourcemap 方案,并支持更多功能,如:错误调用栈,log 信息,issue管理,多项目,多用户,提供多种语言客户端等,

这里不过多叙述,之后在搭建sentry服务时,会再补篇博文

补充:node服务端错误处理机制

全栈开发,后端采用express库,在这里补充一下,node服务的错误处理方案

错误分类

一般错误处理:如某种回退,基本上只是说:“有错误,请再试一次或联系我们”。这并不是特别聪明,但至少通知用户,有地方错了——而不是无限加载或进行类似地处理

特殊错误处理为用户提供详细信息,让用户了解有什么问题以及如何解决它,例如,有信息丢失,数据库中的条目已经存在等等

步骤

1. 构建一个自定义 Error 构造函数:让我们方便地获得堆栈跟踪

class CustomError extends Error {    constructor(code = 'GENERIC', status = 500, ...params) {        super(...params)        if (Error.captureStackTrace) {            Error.captureStackTrace(this, CustomError)        }        this.code = code        this.status = status    }}module.exports = CustomError

2.处理路由:对于每一个路由,我们要有相同的错误处理行为

wT:在默认情况下,由于路由都是封装的,所以 Express 并不真正支持那种方式

解决:实现一个路由处理程序,并把实际的路由逻辑定义为普通的函数。这样,如果路由功能(或任何内部函数)抛出一个错误,它将返回到路由处理程序,然后可以传给前端

const express = require('express')const router = express.Router()const CustomError = require('../CustomError')router.use(async (req, res) => {    try {        const route = require(`.${req.path}`)[req.method]        try {            const result = route(req) // We pass the request to the route function            res.send(result) // We just send to the client what we get returned from the route function        } catch (err) {            /*            This will be entered, if an error occurs inside the route function.            */            if (err instanceof CustomError) {                /*                 In case the error has already been handled, we just transform the error                 to our return object.                */                return res.status(err.status).send({                    error: err.code,                    description: err.message,                })            } else {                console.error(err) // For debugging reasons                // It would be an unhandled error, here we can just return our generic error object.                return res.status(500).send({                    error: 'GENERIC',                    description: 'Something went wrong. Please try again or contact support.',                })            }        }    } catch (err) {        /*         This will be entered, if the require fails, meaning there is either         no file with the name of the request path or no exported function         with the given request method.        */        res.status(404).send({            error: 'NOT_FOUND',            description: 'The resource you tried to access does not exist.',        })    }})module.exports = router// 实际路由文件const CustomError = require('../CustomError')const GET = req => {    // example for success    return { name: 'Rio de Janeiro' }}const POST = req => {    // example for unhandled error    throw new Error('Some unexpected error, may also be thrown by a library or the runtime.')}const DELETE = req => {    // example for handled error    throw new CustomError('CITY_NOT_FOUND', 404, 'The city you are trying to delete could not be found.')}const PATCH = req => {    // example for catching errors and using a CustomError    try {        // something bad happens here        throw new Error('Some internal error')    } catch (err) {        console.error(err) // decide what you want to do here        throw new CustomError(            'CITY_NOT_EDITABLE',            400,            'The city you are trying to edit is not editable.'        )    }}module.exports = {    GET,    POST,    DELETE,    PATCH,}

3.构建全局错误处理机制

process.on('uncaughtException', (error: any) => {    logger.error('uncaughtException', error)})process.on('unhandledRejection', (error: any) => {    logger.error('unhandledRejection', error)})


总结:

1.可疑区域增加 Try-Catch
2.全局监控 JS 异常 window.onerror
3.全局监控静态资源异常 window.addEventListener
4.捕获没有 Catch 的 Promise 异常:unhandledrejection
5.VUE errorHandler 和 React componentDidCatch
6.监控网页崩溃:window 对象的 load 和 beforeunload

7.跨域 crossOrigin 解决


原文来自:https://segmentfault.com/a/1190000019226851



  • 上一条:
    vue组件事件属性穿透
    下一条:
    Vue用Canvas生成二维码合成海报并解决清晰度问题
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 使用 Alpine.js 排序插件对元素进行排序(0个评论)
    • 在js中使用jszip + file-saver实现批量下载OSS文件功能示例(0个评论)
    • 在vue中实现父页面按钮显示子组件中的el-dialog效果(0个评论)
    • 使用mock-server实现模拟接口对接流程步骤(0个评论)
    • vue项目打包程序实现把项目打包成一个exe可执行程序(0个评论)
    • 近期文章
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-03
    • 2018-04
    • 2018-05
    • 2018-06
    • 2018-09
    • 2018-11
    • 2018-12
    • 2019-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2021-04
    • 2021-05
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客