@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错误怎么实现?
复制出来
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
@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 的洋葱模型
谢谢
Most helpful comment
把router层的app.jwt去掉,直接在controller层做jwt验证,通过try catch可以获取到错误