koa, express接口错误处理

2020-07-23  本文已影响0人  awayisblue

koa错误处理

使用koa的时候,对错误的处理是比较方便直接的,我们可以写一个以下的中间件来处理错误:

module.exports = function () {

  return async (ctx, next) => {

    try {

      await next()

      // 通过ctx来判断程序执行状态,进行一些额外的处理

    } catch (err) {

      // 处理throw错误

    }

  }

}

这个中间件需要在路由之前引入。这样next就是去处理路由的业务逻辑,并且由于try catch的存在, throw出来的error都可以被捕获到并返回给接口调用方。这样可以有一个强一致的接口返回数据结构,避免造成前端代码错误。

同时,可以在接口里自定义错误格式,比如接口参数错误,登录密码错误等,在接口代码里throw出来,然后在这个中间件里进行统一识别处理,这样,可以做到错误的统一处理,代码可以写的比较简洁。

express错误处理

用过express的人都知道,express的错误是通过next(err)来传导的,这样,throw的错误假如没有通过代码去捕获的话,很容易造成整个express app都崩溃。很多人写代码都是在每个中间件里进行try catch, 然后把catch到的err通过next(err)通知express进行错误处理。这样会有很多重复的代码,而且无法做到接口代码无感知处理接口错误。

我们可以写一个适配器处理这个问题:

module.exports = class AppRouteAdapter {

  constructor (realApp) {

// realApp是express实例

    this.realApp = realApp

// 这里支持get, put,post,patch, delete方法,假如需要支持新的方法,可以加在这个数组里面

    let methods = ['get', 'put', 'post', 'patch', 'delete']

    methods.forEach((action) => {

// 动态添加http请求方法

      this[action] = this.method.bind(this, action)

    })

  }

  _isAsyncFunc (func) {

    // console.log(this.curApi, func)

    const string = func.toString().trim()

    return string.indexOf('async') === 0

  }

  _toAsyncMiddleware (middleware) {

    let realApp = this.realApp

    return this._isAsyncFunc(middleware) ? middleware : async function () { middleware.apply(realApp, Array.prototype.slice.call(arguments, 0)) }

  }

  // 把路由中间件合并成一个,支持中间件嵌套执行。

  _combineMiddleware (middlewares = []) {

    let realApp = this.realApp

    return async function (req, res, next) {

      let nextMiddleware = next

      for (let i = middlewares.length - 1; i >= 0; i--) {

        nextMiddleware = middlewares[i].bind(realApp, req, res, nextMiddleware)

      }

      return nextMiddleware()

    }

  }

  route (api) {

    this.curApi = api

    return this

  }

  method (action, ...middlewares) {

    let newMiddlewares = middlewares.map((middleware) => {

      let asyncMiddleware = this._toAsyncMiddleware(middleware)

      return async (req, res, next) => {

        return asyncMiddleware(req, res, next).catch(next)

      }

    })

    // 假如要支持中间件嵌套,可以使用this._combineMiddleware来合并成一个中间件

    // this.realApp.route(this.curApi)[action](this._combineMiddleware(newMiddlewares))

    this.realApp.route(this.curApi)[action](newMiddlewares)

  }

}

假设我们的路由注册方式是这样的:

app.route('/api/example').get((req, res, next) => next(), (req, res, next) => res.send('response'))

其中, app是express实例, 注册了/api/example的路由,使用get方法,有两个中间件。

我们使用:

let adapter = new AppRouteAdapter(app)

adapter.route('/api/example').get((req, res, next) => next(), (req, res, next) => res.send('response'))

把app换成adapter, 来进行路由注册。

那么这个adapter做了什么呢?

1. 把2个中间件都转换成async function,

2. 所有async的中间件使用.catch(next)进行统一错误捕获,并把错误传给next,让express的错误处理中间件可以进行处理。

这样,也就实现了前面koa说拥有的那些错误处理的优点。

上一篇 下一篇

猜你喜欢

热点阅读