Node服务端项目中优雅地处理异常和客户端响应

Nodejs7 个月前6746

在平时的服务端项目开发中,异常的处理是必不可少的,但如果处理方式不当,就会造成代码的臃肿,随着项目越来越大,有可能会造成难以维护的局面。下面以Koa2框架为例,通过异常类与中间件的结合,记录一种比较优雅的处理方案

一、异常类编写

在前后端分离的web开发中,接口的响应字段一般分为 datacodemessage(当然也可以自定义其它字段) ,有了这三个字段,客户端就可以进行相应的业务处理,下面的异常类专门负责客户端的响应字段。在项目根目录新建 core 文件夹,用来存放项目的核心文件,在该文件夹下新建一个httpException.js文件。

// 创建HttpException基类,下面的异常类都继承于该类
class HttpException extends Error {
    constructor(msg, code = 1000, status = 500) {
        super()
        this.msg = msg
        this.code = code
        this.status = status
    }
}

// 成功的处理,没错,也可以继承HttpException基类,专门负责正常的数据响应
class HttpSuccess extends HttpException {
    constructor(data, code = 200, msg = "成功") {
        super()
        this.data = data
        this.code = code
        this.msg = msg
        this.status = 200
    }
}

//参数异常类
class ParameterException extends HttpException {
    constructor(msg = "参数错误", code = 400, status = 200) {
        super()
        this.msg = msg
        this.code = code
        this.status = status
    }
}

// 404
class NotFount extends HttpException {
    constructor(msg = "资源未找到", code = 404, status = 404) {
        super()
        this.msg = msg
        this.code = code
        this.status = status
    }
}

// 授权失败
class AuthFailed extends HttpException {
    constructor(msg = "授权失败", code = 1004, status = 401) {
        super()
        this.msg = msg
        this.code = code
        this.status = status
    }
}

// 禁止访问
class Forbidden extends HttpException {
    constructor(msg = "禁止访问", code = 10006, status = 403) {
        super()
        this.msg = msg
        this.code = code
        this.status = status
    }
}

module.exports = {
    HttpException,
    HttpSuccess,
    ParameterException,
    NotFount,
    AuthFailed,
    Forbidden,
}

上面是根据 http 协议的状态码来定义的,这里只给出几个例子,当然也可以自定义其它类型的。下面通过编写一个全局异常捕获中间件,就可以达到我们的目的了

二、全局异常捕获中间件

在项目根目录新建一个middleware文件夹,用来存放自定义的中间件,在该文件夹下新建 cacheError.js 文件,里面编写异常捕获的逻辑。

// 首先引入 HttpException 异常类
const { HttpException } = require('../core/httpException')

//基于 HttpException 的异常捕获
const cacheError = () => {
    return async (ctx, next) => {
        try {
            await next()
        } catch (error) {
            // 通过 instanceof 来判断该错误是否属于 HttpException 的实例
            if (error instanceof HttpException) {
                // 这里统一响应数据
                ctx.body = {
                    data: error.data || null,
                    code: error.code,
                    message: error.msg,
                    request: `${ctx.method} ${ctx.path}`
                }
                ctx.status = error.status
            } else {
                // 未知错误 统一响应服务器异常
                ctx.body = {
                    data: null,
                    code: 500,
                    message: "服务器异常",
                    request: `${ctx.method} ${ctx.path}`
                }
                ctx.status = 500
            }
        }
    }
}

module.exports = cacheError

到这里,异常类和中间件都写好了,下面开始引入使用

三、在入口文件引入中间件

在根目录新建项目的入口文件为 app.js ,然后在里面引入上面编写好的全局异常捕获中间件,由于只是案例,这里把路由写在了这里,实际开发中是需要把路由单独拆分出来的

const Koa = require('koa')
const app = new Koa()
const router = require('koa-router')()
// 全局异常捕获中间件
const cacheError = require('./middleware/cacheError')

// 引入 HttpSuccess 异常类
const { HttpSuccess } = require('./core/httpException')

app.use(cacheError())

router.get('/', async (ctx, next) => {
    // 在这里抛出 HttpSuccess 异常,会被cacheError中间件捕获,  
    // 其作用就相当于 ctx.body = { data:'hello koa2', code:200, message:"成功" }
    throw new HttpSuccess('hello koa2')
})

// routes
app.use(router.routes(), router.allowedMethods())

app.listen(3000, () => {
    console.log(`start port 3000`)
})

以抛出自定义的 httpException 异常,然后通过中间件捕获的方式来代替 ctx.body,当编写的Api越来越多的时候,就会觉得这种处理方式真是太棒了。

测试的时候不要忘了执行以下命令:
初始化npm: npm init
安装koa和koa-router:npm i koa koa-router --save
启动服务:node app

至此,一个简单的全局异常处理以及客户端响应的方案就完成了。这只是一个小案例,在实际项目开发中就复杂了,也正因如此,我们才需要做各种封装,才能开发出易于拓展和维护的项目。

以后作者会发布更多实用的内容,如果该文章于您有所帮助,就点赞或分享给你的小伙伴吧!

3 条评论

    文章不错,大佬有空可以回访一下https://yxb.qiuyi.cn/ 磕头了 

    0

    用nodejs做服务端的不多吧 

    不会Node的厨师不是好歌手。哈哈,后端开发Java的最多 

    0
    0

    挺细致👍 

    嘿嘿。常来看看呦 

    1
    1