Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 386|回复: 0

nodejs异常处理过程/获取nodejs异常类型/写一个eggjs异常处理中间件

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-4-30 11:01:40 | 显示全部楼层 |阅读模式

    前言

    今天想写一下eggjs的自定义异常处理中间件,在写的时候遇到了问题,这个错误我捕获不到类型??

    处理过程,不喜欢看过程的朋友请直接看解决方法和总结

    看一下是什么:
    在这里插入图片描述

    抛出的异常是检验失败异常Validation Failed (code: invalid_param)

    我写了个异常处理中间件,用来处理业务中的异常

    module.exports = (options, app) => {
    
      return async function testMiddleware(ctx, next) {
    
        try{
          await next();
        }
        catch (err) {
          // 记录到日志
          ctx.logger.error(err);
          ctx.throw(err);
        }
      };
    };
    
    

    具体思路是想要根据异常的类型来实现自定义的处理,如验证失败就不走onerror。如果不是想要处理的错误就ctx.throw(),丢给onerror继续处理。

    看了下抛出的错误类型是:UnprocessableEntityError
    在这里插入图片描述

    也没多想,就用instanceof判断一下吧:

    module.exports = (options, app) => {
    
      return async function testMiddleware(ctx, next) {
    
        try{
          await next();
        }
        catch (err) {
          if (err instanceof UnprocessableEntityError) {	
            // 如果是这个错误那么就自己处理,否则就抛出
            // 记录到日志
            ctx.logger.error(err);
            ctx.body = {
              code: err.status,
              err
            }
          } else {
            ctx.throw(err);
          }
        }
      };
    };
    
    

    然后就报了‘UnprocessableEntityError’ undefine错误。。

    对的,UnprocessableEntityError我没有引入,nodejs自带也没这个错误?那这个错误哪来的?

    接着我顺着错误去找抛出的源头,找到了这个:

    在这里插入图片描述

    this.throw是koa 的throw方法:

    在这里插入图片描述

    在node_modules_koa@2.7.0@koa\lib\context.js的throw函数抛出了这个错误,
    具体使用的是createError这个函数,再去代码目录下找createError:

    webstorm ctrl+鼠标左键定位跳转一下,发现原来使用的是http-errors模块里面的里面的createError方法,下面是具体的函数内容:

    // node_modules\_http-errors@1.7.3@http-errors\index.js
    
    /**
     * Create a new HTTP Error.
     *
     * @returns {Error}
     * @public
     */
    
    function createError () {
      // so much arity going on ~_~
      var err
      var msg
      var status = 500
      var props = {}
      for (var i = 0; i < arguments.length; i++) {
        var arg = arguments
        if (arg instanceof Error) {		// 如果参数类型就是Error那么err就是arg
          err = arg
          status = err.status || err.statusCode || status
          continue	// 跳过以下代码,进入下一轮循环
        }
        switch (typeof arg) {
          case 'string':		// 如果arg是string 那么err的msg就是arg
            msg = arg
            break
          case 'number':	// 如果是number 那么错误的status就是arg,这里要求statu是第一个参数
            status = arg
            if (i !== 0) {
              deprecate('non-first-argument status code; replace with createError(' + arg + ', ...)')
            }
            break
          case 'object':	// 如果是类,那么把类挂载到err上
            props = arg
            break
        }
      }
    // 循环完毕了,来判断一下状态码
      if (typeof status === 'number' && (status < 400 || status >= 600)) {
        deprecate('non-error status code; use only 4xx or 5xx status codes')
      }
    
      if (typeof status !== 'number' ||
        (!statuses[status] && (status < 400 || status >= 600))) {
        status = 500
      }
    
      // constructor
      var HttpError = createError[status] || createError[codeClass(status)] 
      // 我们传的是422,所以返回了UnprocessableEntityError这个构造器
      
      if (!err) {	// 如果不是直接传入Error
        // create error
        err = HttpError	// 如果HttpError为空,HttpError里面没有这个错误
          ? new HttpError(msg)  // 执行到这一步,返回一个新的错误,
          : new Error(msg || statuses[status])	
        Error.captureStackTrace(err, createError)  // 传入堆栈信息
      }
    
      if (!HttpError || !(err instanceof HttpError) || err.status !== status) { //不执行
        // add properties to generic error
        err.expose = status < 500
        err.status = err.statusCode = status
      }
    
      for (var key in props) {
        if (key !== 'status' && key !== 'statusCode') {	//将数据挂载上去
          err[key] = props[key]
        }
      }
    
      return err
    }
    

    大概搞明白了

    就是validate在抛出异常之后,调用了koa的throw又调用了http-errors里面的createError,createError先去找有咩有这个http错误,常见的什么404啊403啊500啊之类的,没找到就直接把用Error构造,找到了就用对应的错误类型构造,这些类型构造又是存在:node_modules/koa/node_modules/http-errors/node_modules/statuses/index.js里面的,比如上面的422
    在这里插入图片描述
    对应的就是UnprocessableEntityError这个异常。

    解决方法

    到了这里,解决就变的很轻松了,我们要捕获的异常是UnprocessableEntityError,那么可以使用err.name来获取错误的名字,获取到了之后,再根据
    在这里插入图片描述
    validate抛出的固定错误码'Validation Failed'来确定错误。
    实际上也可以直接根据这个错误码来判断,这个错误码经历了HttpError的洗礼之后变成了message,可以通过err.message来获取。
    那么代码如下:

    module.exports = (options, app) => {
    
      return async function testMiddleware(ctx, next) {
    
        try{
          await next();
        }
        catch (err) {
          if (err.message === 'Validation Failed') {
         	// 记录到日志
            ctx.logger.error(err);
            ctx.body = {
              code: err.status,
              err
            }
          } else {
            ctx.throw(err);
          }
        }
      };
    };
    
    

    再次打开浏览器尝试一下,这个异常被正确的返回给前端了:
    在这里插入图片描述

    总结一下

    1. 错误类型,既错误名可以使用err.name获取
    2. 对应的错误消息(相比HttpError更精细的)使用err.message获取
    3. 错误哪怕被自己处理了也还是写入日志,logger.error()一下比较好
    4. 你不想处理的错误还是交给onerror来办,使用ctx.throw丢给它
    5. 记得处理错误要返回信息,既设置ctx.body,不然会返回404的

    谢谢观看,有什么问题欢迎留言评论,看到尽量会回复。。。

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-19 07:09 , Processed in 0.065626 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表