前言

今天想写一下eggjs的自定义异常处理中间件,在写的时候遇到了问题,这个错误我捕获不到类型??

处理过程,不喜欢看过程的朋友请直接看解决方法和总结

看一下是什么:

抛出的异常是检验失败异常Validation Failed (code: invalid_param)

我写了个异常处理中间件,用来处理业务中的异常

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继续处理。

看了下抛出的错误类型是:UnprocessableEntityError

也没多想,就用instanceof判断一下吧:

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错误。。

对的,UnprocessableEntityError我没有引入,nodejs自带也没这个错误?那这个错误哪来的?

接着我顺着错误去找抛出的源头,找到了这个:

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);
}
}
};
};

再次打开浏览器尝试一下,这个异常被正确的返回给前端了:

总结一下

  1. 错误类型,既错误名可以使用err.name获取
  2. 对应的错误消息(相比HttpError更精细的)使用err.message获取
  3. 错误哪怕被自己处理了也还是写入日志,logger.error()一下比较好
  4. 你不想处理的错误还是交给onerror来办,使用ctx.throw丢给它
  5. 记得处理错误要返回信息,既设置ctx.body,不然会返回404的

谢谢观看,有什么问题欢迎留言评论,看到尽量会回复。。。

nodejs异常处理过程/获取nodejs异常类型/写一个eggjs异常处理中间件的更多相关文章

  1. 写一个eggjs权限验证中间件

    关于中间件 https://eggjs.org/zh-cn/basics/middleware.html 官方文档说的很清楚了,不再叙述. 我们要达到怎么样一个效果? 用户没有登录不能访问一些特定的页 ...

  2. 异常处理的方式二:throws+异常类型

    package com.yhqtv.demo01Exception; import java.io.File; import java.io.FileInputStream; import java. ...

  3. 一、NodeJS入门——准备工作(1)——NodeJS的安装

    目录 1.介绍 2.nodejs下载 3.nodejs安装 4.nodejs的简单实用 5.nodejs的经典入门:hello world 6.总结 1    介绍 这是一系列的内容主要是关于我在学习 ...

  4. springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。为了区别不同的异常通常根据异常类型自定义异常类,这里我们创建一个自定义系统异常,如果controller、service、dao抛出此类异常说明是系统预期处理的异常信息。

    springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑. 1.1 异常处理思路 系统中异常包括两类:预期异常和运行时异常RuntimeEx ...

  5. 用 nodejs 写一个命令行工具 :创建 react 组件的命令行工具

    用 nodejs 写一个命令行工具 :创建 react 组件的命令行工具 前言 上周,同事抱怨说 react 怎么不能像 angular 那样,使用命令行工具来生成一个组件.对呀,平时工作时,想要创建 ...

  6. nodejs 通过 get获取数据修改redis数据

    如下代码是没有报错的正确代码 我通过https获取到数据 想用redis set一个键值存储 现在我掉入了回调陷阱res.on 里面接收到的数据是data 里面如果放入 client.on('conn ...

  7. linux系统下nodejs安装过程随记

    首先下载适合的版本.这里我使用的是node v.10.36 先介绍编译安装的详细过程. 下载该版本: wget http://nodejs.org/dist/v0.10.36/node-v0.10.3 ...

  8. python第三十课--异常(异常处理定义格式和常见类型)

    演示: 1).异常处理的定义格式: 2).常见的运行时异常类型: try: print(10/0) num=int('132a') except Exception as e: print('出错了. ...

  9. nodejs:使用puppeteer在服务器中构建一个获取电影电视剧剧集的接口

    首先我们看下数据来源: 来源于这个网站:https://z1.m1907.cn/ 可以说这个网站上能找到很多你想看的很多电影或电视剧,最重要的是很多电影电视剧在别的网站是收费的,但是在这里看是免费的, ...

随机推荐

  1. [摘录] 当页[ModalRoute.of(context)]路由属性详解

    ModalRoute.of(context) API可以获取当前路由对象,通过它我们可以获取关于当前页面的所有属性: 属性: isActive 当前路由是都位于navigator中:如果该路由acti ...

  2. Java 之 Set 接口

    一.Set 概述 java.util.Set 接口继承 collection 接口,它与 Collection 接口中的方法基本一致,并没有对 Collection 接口进行功能上的扩充,只是比 Co ...

  3. WIN10分盘

    https://jingyan.baidu.com/article/73c3ce28325dcde50243d94d.html

  4. MongoDB 分片集群实战

    背景 在如今的互联网环境下,海量数据已随处可见并且还在不断增长,对于如何存储处理海量数据,比较常见的方法有两种: 垂直扩展:通过增加单台服务器的配置,例如使用更强悍的 CPU.更大的内存.更大容量的磁 ...

  5. k8s的pod或者ns资源一直terminating删除办法

    假设你要删掉的ns资源,发现一直删不了处于terminating状态 1.首先试一下先把这个ns的所有pod都删掉kubectl delete pod --all -n <terminating ...

  6. JQuery学习笔记之属性与样式

    .attr()与.removeAttr() attr()有4个表达式 attr(传入属性名):获取属性的值 attr(属性名, 属性值):设置属性的值 attr(属性名,函数值):设置属性的函数值 a ...

  7. php解释器模式( interpreter pattern)

    ... <?php /* The interpreter pattern specifies how to evaluate language grammar or expressions. W ...

  8. Find the median(2019年牛客多校第七场E题+左闭右开线段树)

    题目链接 传送门 题意 每次往集合里面添加一段连续区间的数,然后询问当前集合内的中位数. 思路 思路很好想,但是卡内存. 当时写的动态开点线段树没卡过去,赛后机房大佬用动态开点过了,\(tql\). ...

  9. 2019年杭电多校第二场 1008题Harmonious Army(HDU6598+最小割+建图)

    题目链接 传送门 题意 有\(n\)个士兵,要你给他们分配职业.有\(m\)对关系,对于某一对关系\(u,v\),如果同为勇士则总能力增加\(a\),同法师则增加\(c\),一个勇士一个法师增加\(\ ...

  10. php静态方法

    静态方法 (1)静态方法不能访问这个类中的普通属性,因为那些属性属于一个对象,但可以访问静态属性: (2)从当前类(不是子类)中访问静态方法或属性,可以使用 self 关键字,self 指向当前类,就 ...