今天想写一下eggjs的自定义异常处理中间件,在写的时候遇到了问题,这个错误我捕获不到类型??前端
看一下是什么:
node
抛出的异常是检验失败异常Validation Failed (code: invalid_param)
web
我写了个异常处理中间件,用来处理业务中的异常浏览器
module.exports = (options, app) => { return async function testMiddleware(ctx, next) { try{ await next(); } catch (err) { // 记录到日志 ctx.logger.error(err); ctx.throw(err); } }; };
具体思路是想要根据异常的类型来实现自定义的处理,如验证失败就不走onerror。若是不是想要处理的错误就ctx.throw(),丢给onerror继续处理。app
看了下抛出的错误类型是:UnprocessableEntityError
koa
也没多想,就用instanceof判断一下吧:webstorm
module.exports = (options, app) => { return async function testMiddleware(ctx, next) { try{ await next(); } catch (err) { if (err instanceof UnprocessableEntityError) { // 若是是这个错误那么就本身处理,不然就抛出 // 记录到日志 ctx.logger.error(err); ctx.body = { code: err.status, err } } else { ctx.throw(err); } } }; };
而后就报了‘UnprocessableEntityError’ undefine错误。。async
对的,UnprocessableEntityError我没有引入,nodejs自带也没这个错误?那这个错误哪来的?函数
接着我顺着错误去找抛出的源头,找到了这个:this
this.throw是koa 的throw方法:
在node_modules_koa@2.7.0@koa\lib\context.js的throw函数抛出了这个错误,
具体使用的是createError这个函数,再去代码目录下找createError:
webstorm ctrl+鼠标左键定位跳转一下,发现原来使用的是http-errors模块里面的里面的createError方法,下面是具体的函数内容:
// node_modules\_http-errors@1.7.3@http-errors\index.js /** * Create a new HTTP Error. * * @returns {Error} * @public */ function createError () { // so much arity going on ~_~ var err var msg var status = 500 var props = {} for (var i = 0; i < arguments.length; i++) { var arg = arguments[i] if (arg instanceof Error) { // 若是参数类型就是Error那么err就是arg err = arg status = err.status || err.statusCode || status continue // 跳过如下代码,进入下一轮循环 } switch (typeof arg) { case 'string': // 若是arg是string 那么err的msg就是arg msg = arg break case 'number': // 若是是number 那么错误的status就是arg,这里要求statu是第一个参数 status = arg if (i !== 0) { deprecate('non-first-argument status code; replace with createError(' + arg + ', ...)') } break case 'object': // 若是是类,那么把类挂载到err上 props = arg break } } // 循环完毕了,来判断一下状态码 if (typeof status === 'number' && (status < 400 || status >= 600)) { deprecate('non-error status code; use only 4xx or 5xx status codes') } if (typeof status !== 'number' || (!statuses[status] && (status < 400 || status >= 600))) { status = 500 } // constructor var HttpError = createError[status] || createError[codeClass(status)] // 咱们传的是422,因此返回了UnprocessableEntityError这个构造器 if (!err) { // 若是不是直接传入Error // create error err = HttpError // 若是HttpError为空,HttpError里面没有这个错误 ? new HttpError(msg) // 执行到这一步,返回一个新的错误, : new Error(msg || statuses[status]) Error.captureStackTrace(err, createError) // 传入堆栈信息 } if (!HttpError || !(err instanceof HttpError) || err.status !== status) { //不执行 // add properties to generic error err.expose = status < 500 err.status = err.statusCode = status } for (var key in props) { if (key !== 'status' && key !== 'statusCode') { //将数据挂载上去 err[key] = props[key] } } return err }
就是validate在抛出异常以后,调用了koa的throw又调用了http-errors里面的createError,createError先去找有咩有这个http错误,常见的什么404啊403啊500啊之类的,没找到就直接把用Error构造,找到了就用对应的错误类型构造,这些类型构造又是存在:node_modules/koa/node_modules/http-errors/node_modules/statuses/index.js
里面的,好比上面的422
对应的就是UnprocessableEntityError这个异常。
到了这里,解决就变的很轻松了,咱们要捕获的异常是UnprocessableEntityError,那么能够使用err.name来获取错误的名字,获取到了以后,再根据
validate抛出的固定错误码'Validation Failed'来肯定错误。
实际上也能够直接根据这个错误码来判断,这个错误码经历了HttpError的洗礼以后变成了message,能够经过err.message来获取。
那么代码以下:
module.exports = (options, app) => { return async function testMiddleware(ctx, next) { try{ await next(); } catch (err) { if (err.message === 'Validation Failed') { // 记录到日志 ctx.logger.error(err); ctx.body = { code: err.status, err } } else { ctx.throw(err); } } }; };
再次打开浏览器尝试一下,这个异常被正确的返回给前端了: