错误分类之后,我们抛错误的时候就变得更加直观了:
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, 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,那么我们要做的是添加错误处理的中间件:
通过这种方式,我们就能优雅地处理 Restful API 中的错误信息了。
Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx