Node服务端项目中优雅地处理异常和客户端响应
在平时的服务端项目开发中,异常的处理是必不可少的,但如果处理方式不当,就会造成代码的臃肿,随着项目越来越大,有可能会造成难以维护的局面。下面以Koa2框架为例,通过异常类与中间件的结合,记录一种比较优雅的处理方案
一、异常类编写
在前后端分离的web开发中,接口的响应字段一般分为 data
、 code
、message
(当然也可以自定义其它字段) ,有了这三个字段,客户端就可以进行相应的业务处理,下面的异常类专门负责客户端的响应字段。在项目根目录新建 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
至此,一个简单的全局异常处理以及客户端响应的方案就完成了。这只是一个小案例,在实际项目开发中就复杂了,也正因如此,我们才需要做各种封装,才能开发出易于拓展和维护的项目。
以后作者会发布更多实用的内容,如果该文章于您有所帮助,就点赞或分享给你的小伙伴吧!
文章不错,大佬有空可以回访一下https://yxb.qiuyi.cn/ 磕头了
用nodejs做服务端的不多吧
不会Node的厨师不是好歌手。哈哈,后端开发Java的最多
挺细致👍
嘿嘿。常来看看呦