从零搭建我的博客网站(二)-全局异常处理

对于异常,咱们能够分为 已知异常未知异常node

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

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

中间件的异常

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

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

咱们在控制台获得 UnhandledPromiseRejectionWarning Error:error 错误服务器

咱们如今加上 **app.onerror ** 来拦截这个错误app

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 竟然没有拦截到koa

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

其实吧,咱们违反了 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
}
...
复制代码

通过测试,咱们能够抛出那些未知错误,到此整个中间件编写完成!

相关文章
相关标签/搜索