Restful API 中的错误处理(2)

错误分类之后,我们抛错误的时候就变得更加直观了:

if (!res.body.title) { throw new Error(ERROR.FORMAT_INVALID) } if (!user) { throw new Error(ERROR.LOGIN_REQUIRED) } if (!post) { throw new Error(ERROR.DATA_NOT_FOUND) } if (post.creator.id !== user.id) { throw new Error(ERROR.PERMISSION_DENIED) }

这种形式比上面的写死状态码的方式方便很多,而且维护起来也更加简单。
但有一个问题,就是不能根据错误类型来返回指定的错误信息。

自定义错误类型

要实现根据错误类型来返回指定的错误信息,我们可以通过自定义错误的方式来实现。
假设我们自定义错误的结构如下:

{ "type": "", "code": 0, "message": "", "detail": "" }

我们需要做到如下几点:

根据错误类型来自动设置type, code, message

detail 为可选项,用来描述该错误的具体原因

const ERROR = { FORMAT_INVALID: 'FORMAT_INVALID', DATA_NOT_FOUND: 'DATA_NOT_FOUND', DATA_EXISTED: 'DATA_EXISTED', DATA_INVALID: 'DATA_INVALID', LOGIN_REQUIRED: 'LOGIN_REQUIRED', PERMISSION_DENIED: 'PERMISSION_DENIED' } const ERROR_MAP = { FORMAT_INVALID: { code: 1, message: 'The request format is invalid' }, DATA_NOT_FOUND: { code: 2, message: 'The data is not found in database' }, DATA_EXISTED: { code: 3, message: 'The data has exist in database' }, DATA_INVALID: { code: 4, message: 'The data is invalid' }, LOGIN_REQUIRED: { code 5, message: 'Please login first' }, PERMISSION_DENIED: { code: 6, message: 'You have no permission to operate' } } class CError extends Error { constructor(type, detail) { super() Error.captureStackTrace(this, this.constructor) let error = ERROR_MAP[type] if (!error) { error = { code: 999, message: 'Unknow error type' } } this.name = 'CError' this.type = error.code !== 999 ? type : 'UNDEFINED' this.code = error.code this.message = error.message this.detail = detail } }

自定义好错误之后,我们调用起来就更加简单了:

// in controller if (!user) { throw new CError(ERROR.LOGIN_REQUIRED, 'You should login first') } if (!req.body.title) { throw new CError(ERROR.FORMAT_INVALID, 'Title is required') } if (!post) { throw new CError(ERROR.DATA_NOT_FOUND, 'The post you required is not found') }

最后,还剩下一个问题,根据错误类型来设置状态码,然后返回错误信息给客户端。

捕获错误信息

在 Controller 中抛出自定义错误后,我们需要捕获该错误,才能返回给客户端。
假设我们使用 koa 2 作为 web 框架来开发 restful api,那么我们要做的是添加错误处理的中间件:

module.exports = async function errorHandler (ctx, next) { try { await next() } catch (err) { let status switch (err.type) { case ERROR.FORMAT_INVALID: case ERROR.DATA_EXISTED: case ERROR.DATA_INVALID: status = 400 break case ERROR.LOGIN_REQUIRED: status = 401 case ERROR.PERMISSION_DENIED: status = 403 case ERROR.DATA_NOT_FOUND: status = 404 break default: status = 500 } ctx.status = status ctx.body = err } } // in app.js app.use(errorHandler) app.use(router.routes())

通过这种方式,我们就能优雅地处理 Restful API 中的错误信息了。

Linux公社的RSS地址https://www.linuxidc.com/rssFeed.aspx

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b2ac09538cd21b97c1ddb7aff9eb9a17.html