美文网首页
从零构架个人博客网站(二)-全局异常处理

从零构架个人博客网站(二)-全局异常处理

作者: 席坤 | 来源:发表于2020-03-07 11:41 被阅读0次


    对于异常,我们可以分为 已知异常未知异常

    已知异常就是程序中能够知道的异常,如:客户端参数传递错误,服务端抛出异常、如客户端无权限访问等等这类,这类错误就是已知异常。

    未知异常就是程序中不能预想的错误,最常见的服务器程序抛出状态码 500 的异常。又比如我们单词拼写错误,导致程序无法运行等等,这种就是未知异常。

    中间件的异常

    我们在中间件抛出一个异常看看

    app.use((ctx, next) => {
        throw Error('error');
        ctx.msg += 'world';
        next();
    });
    

    我们在控制台得到 UnhandledPromiseRejectionWarning Error:error 错误

    我们现在加上 **app.onerror ** 来拦截这个错误

    
    app.use((ctx, next) => {
        throw Error('error');
        ctx.msg += 'world';
        next();
    });
    
    app.use(ctx => {
      ctx.body = 'hello word';
    });
    
    app.onerror = (err) => {
      console.log('捕获到了!', err.message);
    }
    

    再次运行,发现 onerror 居然没有拦截到

    查阅官网中记载的错误处理方法 Error Handling

    其实吧,我们违反了 koa 的设计,有两种方法处理这个问题。

    如果不想改成 async 函数,那就在所有 next() 前面加上 return 即可。

    如果是 async 函数,那所有 next 前面加 await 即可

    知道了这个我们开始编写全局异常中间件

    全局异常中间件

    全局异常监听

    编写捕捉异常处理中间件 catchError.js

    const catchError = async (ctx, next) => {
        try {
            await next()
        } catch (error) {
           
        }
    }
    
    module.exports = catchError
    

    在 app.js 加载中间件

    全局异常中间件监听、处理,因此放在所有中间件的最前面

    const catchError = require('./middlewares/exception')
    const app = new Koa()
    app.use(catchError)
    ...
    app.listen(8000) 
    

    我们来测试下能否正确拦截到异常

    const Koa = require('koa');
    const app = new Koa();
    
    const catchError = async (ctx, next) => {
        try {
            await next()
        } catch (error) {
            console.log(error);
        }
    }
    
    app.use(catchError)
    
    app.use((ctx, next) => {
        console.log(a);
    });
    app.listen(8000);
    

    我们运行发现 控制台成功拦截错误 ReferenceError: a is not defined

    定义异常的返回结果

    向上面的 a 是空值 而我们使用了它,导致空指针异常,这类肯定是属于我们前面说的未知异常。那我们怎么区分是已知还是未知呢?

    在服务器接口开发中,一个异常的返回结果,通常包含有:

    • msg:异常信息
    • code:Http 状态码
    • errorCode:自定义的异常状态码

    因此我们可以定义 HttpException 只要是出现这异常属于HttpException都属于已知异常。

    // 定义HttpException继承Error这个类
    class HttpException extends Error {
    
        constructor(msg = '服务器异常', errorCode = 500, code = 400) {
            super()
            /**
             * 错误信息
             */
            this.msg = msg
            /**
             * Http 状态码
             */
            this.code = code
            /**
             * 自定义的异常状态码
             */
            this.errorCode = errorCode
    
        }
    }
    

    我们现在改写下中间件那里,区分是已知异常还是未知异常

    const { HttpException } = require("../core/httpException")
    
    const catchError = async (ctx, next) => {
        try {
            await next()
        } catch (error) {
            const isHttpException = error instanceof HttpException
    
            //判断是否是已知错误
            if (isHttpException) {
                ctx.body = {
                    msg: error.msg,
                    errorCode: error.errorCode,
                    request: `${ctx.method} ${ctx.path}`
                }
                ctx.status = error.code
            } else {
                ctx.body = {
                    msg: '服务器出现了未知异常',
                    errorCode: 999,
                    request: `${ctx.method} ${ctx.path}`
                }
                ctx.status = 500
            }
        }
    }
    
    

    Ok,我们现在在 app.js 测试下

    我们启动服务 访问 http://localhost:8000/ 发现抛出了
    {"msg":"服务器出现了未知异常","errorCode":999,"request":"GET /"}

    说明我们自定义的已知错误被拦截到了.

    定义常见的异常状态

    有了上面的 异常的基类,我们很容易定义一些常见的异常,如:参数校验失败

    class ParameterExceptio extends HttpException {
        constructor(msg, errorCode) {
            super()
            this.code = 400;
            this.msg = msg || '参数错误';
            this.errorCode = errorCode || 400;
        }
    }
    

    成功返回

    class Success extends HttpException {
        constructor(msg, errorCode) {
            super()
            this.code = 200;
            this.msg = msg || '成功';
            this.errorCode = errorCode || 200;
        }
    }
    

    权限认证

    class AuthFaild extends HttpException {
        constructor() {
            super()
            this.code = 401;
            this.msg = '认证失败';
            this.errorCode = 1004;
        }
    }
    

    大家可以根据自己业务定义大家需要的异常情况

    开发环境 异常查看

    前面我们在全局异常中间件那里区分了 已知异常异常 和 未知异常。但是返回了一样的错误,这对我们开发环境 调试是不友好的。我们需要在控制台抛出异常,方便我们定位问题

    改写 pack.json 启动命名

      "scripts": {
        "start": "set NODE_ENV=dev&& nodemon --inspect app.js"
      }
    

    我们启动服务后告诉当前是开发环境,前面已经说了,我们只需要在开发环境中抛出未知错误,如下:

     const isHttpException = error instanceof HttpException
    // 开发环境下输出 异常 error
    if (process.env.NODE_ENV === 'dev' && !isHttpException) {
        throw error
    }
    ...
    

    经过测试,我们可以抛出那些未知错误,到此整个中间件编写完成!

    相关文章

      网友评论

          本文标题:从零构架个人博客网站(二)-全局异常处理

          本文链接:https://www.haomeiwen.com/subject/qbuqdhtx.html