关于koa 异常处理这块
发布于 4 年前 作者 chenye2017 4518 次浏览 来自 问答
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

回到顶部