关于koa 异常处理这块
const Koa = require('koa');
const Router = require('koa-router');
let app = new Koa;
let router = new Router();
const auth = async (ctx, next) => {
// let error = new Error('this is an error')
ctx.throw(500)
await next(error)
}
router.get('/:user', auth, (ctx) => {
let user = ctx.params.user;
let name = ctx.params.name;
console.log(error)
ctx.response.type = 'json';
ctx.body = {
user,
name
}
})
app.use(async ( ctx, next) => {
try {
await next()
} catch (err) {
ctx.type = 'json'
ctx.body = {
message : err.message
}
ctx.app.emit('error', err, ctx);
}
})
app.use(router.routes())
app.on('error', (err,ctx) => {
console.log(111)
ctx.type = 'json'
ctx.body = {
message : err.message
}
})
app.listen(8092, () => {
console.log('8092 is listening koa');
})
当我没有加中间件异常处理函数的时候, koa 的on error 事件能触发,但是ctx.type json 不能生效,不知道是什么原因,加上异常处理中间件后,on error 事件中的ctx.type 能生效,有木有大手子能解释一下
2 回复
其实我不建议在router层做这个事情,可以新建一个controller层通过工厂生产出controller器的入口做代理,拦截proxy。否则路由不够直观后面跟着一大长条方法,第二自定义空间有限导致每个方法都要做类似的事情。
下面是针对问题的回答:
这么和你说吧,在发生处理http请求的时候,在中间件发生错误的时候会调用 ctx的onerror方法,而不是只调用了app的on(error,…)方法
// /lib/application.js
handleRequest(ctx, fnMiddleware) {
const res = ctx.res;
res.statusCode = 404;
const onerror = err => ctx.onerror(err);
const handleResponse = () => respond(ctx);
onFinished(res, onerror);
return fnMiddleware(ctx).then(handleResponse).catch(onerror);
}
但是ctx的onerror方法,不仅仅会调用app的on(error,…)方法,还会覆盖你的ctx.type,如下
// /lib/context.js
onerror(err) {
// 省略代码...
// 如果异常之前就被拦截,这里的err就是null,就不会往下走了
if (null == err) return;
if (!(err instanceof Error)) err = new Error(util.format('non-error thrown: %j', err));
// 省略代码...
// 在这里调用了你的on(error)
this.app.emit('error', err, this);
// 省略代码...
// 关键在这里强制设置了ctx.type把你的覆盖了
this.type = 'text';
// 省略代码...
// 发送数据请求结束
res.end(msg);
},
为什么呢?区别就是你使用了处理异常中间件相当于手动只调用了app的on(error,…)方法。而没使用在处理异常中间件的时候就抛错走了ctx的的onerror方法,这个方法不仅仅会调用app的on(error,…)方法,还会覆盖你的ctx.type
不应该调用 ctx.onError,而是应该直接 ctx.throw