egg-jwt错误框架无法捕捉

Created on 21 Nov 2017  ·  19Comments  ·  Source: eggjs/egg

  • Node Version:8.91
  • Egg Version:1.9.0
  • Plugin Name: egg=jwt
  • Plugin Version: 2.2.0
  • Platform:maxOS
  • Mini Showcase Repository:


@okoala

如果不传入Authorization,中间件返回

ctx.throw(401, 'No authentication token found\n');

外面无法捕捉app/middleware/error_handler.js

module.exports = () => {
  return async function(ctx, next) {
    try {
      await next();
    } catch (err) {
      // 注意:自定义的错误统一处理函数捕捉到错误后也要 `app.emit('error', err, this)`
      // 框架会统一监听,并打印对应的错误日志
      ctx.app.emit('error', err, this);
      // 自定义错误时异常返回的格式
      ctx.body = {
        resCode: '100000',
        message: ctx.app.config.env === 'prod' ? 'Internal Server Error' : err.message
      };
    }
  };
};

app/middleware/notfound_handler.js

module.exports = () => {
  return async function(ctx, next) {
    await next();
    if (ctx.status === 404 && !ctx.body) {
      if (ctx.acceptJSON) ctx.body = { error: 'Not Found' };
      else ctx.body = '<h1>Page Not Found</h1>';
    } else if (ctx.status === 401 && !ctx.body) {
      if (ctx.acceptJSON) ctx.body = ctx.helper.error({ msg: '登录失效' });
      else ctx.body = '<h1>该接口需要登录</h1>';
    }
  };
};

直接暴露出去了
Status Code:401 Unauthorized
我测试了在普通的控制器(/app/controller/index.js)里面ctx.throw能进入error_handler.js

module.exports = app => {
  class HomeController extends app.Controller {
    async index(ctx) {
      ctx.body = 'hi, egg';
    }
    async testError(ctx) {
      ctx.throw(401, 'No authentication token found\n');
    }

  }
  return HomeController;
};

返回

{
  "resCode": "100000",
  "message": "No authentication token found\n"
}

我想拦截这个401错误怎么实现?

Most helpful comment

把router层的app.jwt去掉,直接在controller层做jwt验证,通过try catch可以获取到错误

        try {
            const token = this.app.jwt.verify(Authorization, this.app.config.jwt.secret);
            console.log('---token--->', token);
        } catch (err) {
            console.log('token Error', err.message)
        }

All 19 comments

复制出来

config.middleware = [ 'reqJson', 'errorHandler', 'notfoundHandler', 'reqJwt' ];

这样就可以捕捉到了,应该是加载顺序问题;

如果不复制出来,有没有办法调整加载顺序?

https://eggjs.org/zh-cn/core/error-handling.html#自定义统一异常处理 可以通过文档中的这个方式来自定义错误处理,不通过中间件的形式。

onerror好像并不会处理ctx. throw的错误啊;
这个也处理不了他的401错误,
加入了ctx. throw,404,401前端就是404,401,不会变成500;
还有一个就是errorHandler中间件加入了try catch,catch里面就捕捉不到401了,全部都变成了404,
案例app/controller/index.js

    async testError(ctx) {
      ctx.throw(401, 'No authentication token found\n');
    }
module.exports = () => {
  return async function(ctx, next) {
    // await next();
    // ctx.logger.info(ctx.status);
    try {
      await next();
    } catch (err) {
      ctx.logger.info(ctx.status);
    //   // 注意:自定义的错误统一处理函数捕捉到错误后也要 `app.emit('error', err, this)`
    //   // 框架会统一监听,并打印对应的错误日志
    //   // ctx.app.emit('error', err, this);
    //   // 自定义错误时异常返回的格式
    //   // if (ctx.status === 401 && !ctx.body) {
    //   //   if (ctx.acceptJSON) ctx.body = ctx.helper.error({ msg: '登录失效' });
    //   //   else ctx.body = '<h1>该接口需要登录</h1>';
    //   // } else {
    //   //   ctx.body = {
    //   //     resCode: '100000',
    //   //     message: ctx.app.config.env === 'prod' ? 'Internal Server Error' : err.message
    //   //   };
    //   // }
    }
  };
};



md5-0d11e39a48895de64bf6bfaab4100331



2017-11-21 18:03:58,366 INFO 10615 [-/127.0.0.1/-/1ms GET /testError] 404
  1. onError在错误出现的最后一层,也就是洋葱皮模型的最后兜底
  2. 中间件的错误处理会在onError之前执行,如果你捕捉了错误,哪怕没有处理也认为是处理完毕, 由于你在/testError里面没有写关于ctx.body返回的内容所以是404
  3. 建议是不要onError和统一错误处理中间件一起使用吧,很容易混乱的

@chenyulun 我也问过,那个人让我自己写一中间件处理,可以改一下那个源码

把router层的app.jwt去掉,直接在controller层做jwt验证,通过try catch可以获取到错误

        try {
            const token = this.app.jwt.verify(Authorization, this.app.config.jwt.secret);
            console.log('---token--->', token);
        } catch (err) {
            console.log('token Error', err.message)
        }

@ZQun 我是说过期或者验证错误,不是加密错误的捕捉,401错误被当做了代码层面的报错,很难捕捉

我也遇到了这个问题,无法通过中间件或者 onerror 来拦截异常错误,如果无法在框架统一处理异常,这会很麻烦,因为我们很多的业务逻辑是可以通过抛出异常来中断后续流程,达到流程控制的效果,这样可以减少非常多的面条式代码,伪代码:
非抛出异常:

if (!this.isLogin()) {
  ctx.body = {
     code: 401,
     msg: '请登录'
  }
}

if (!this.isAuthorOf()) {
  ctx.body = {
     code: 403,
     msg: '你没有权限'
  }
}

// 或许还有很多...

抛出异常:

this.isLogin()
this.isAuthorOf()

// 或许还有很多

不同的地方在于,中断返回将交给调用的方法来处理:

public isLogin() {
  if (!userData) {
     ctx.throw(401, '请登录')
  }
}

翻了很多文章,发现还是自己手动 try catch 稳妥些

没看明白为啥 无法通过中间件或者 onerror 来拦截异常错 ?

我今天更新下 egg-jwt 吧~

@atian25 刚刚在弄一个最小复现代码的时候,找到了问题所在了,,,原因是我自己没有 await 导致异常无法捕抓,,,感谢您的帮助!

@atzcl 这种按理说应该有 unhandled promise rejection 提示的吧

@atian25 这个还真没有,可以在控制台看到是抛出 nodejs.UnprocessableEntityError 完整异常堆栈信息,并没捕抓到 ,也没有 unhandled promise rejection 信息,我分别在 controller、service 层中抛出的信息都一样,然后刚刚想弄个最小复现来给你们尝试下的,然后顺手加上了 await,发现就可以了,,,基础太差了,,

@okoala 感谢,等下就更新来用~

弱弱地问下:
config.middleware = ['errorHandler','validateSession']
为什么放在前面的中间件还能拦截到后面中间件抛出的错误?我应用的时候是不是要严格去考虑先后顺序的问题?

你需要了解下 Koa 的洋葱模型

你需要了解下 Koa 的洋葱模型

谢谢

Was this page helpful?
0 / 5 - 0 ratings