koa-application继承自events模块,具有发布-订阅功能
1 events模块需要处理error错误
2 Koa错误处理
3 源码分析
3.1 错误处理
对应events模块错误处理,至少存在一个error处理函数来兜底,防止node进程挂掉
// application
callback() {
if (!this.listenerCount('error')) this.on('error', this.onerror);
}
// Default error handler
onerror(err) {
if (!(err instanceof Error)) throw new TypeError(util.format('non-error thrown: %j', err));
if (404 == err.status || err.expose) return;
if (this.silent) return;
const msg = err.stack || err.toString();
console.error();
console.error(msg.replace(/^/gm, ' '));
console.error();
}
};
同时可以自定义错误处理程序,参考2中,集中日志处理,可以多次订阅error事件,来处理自己业务错误的处理程序。
app.on('error', err => {
// 错误处理1
});
app.on('error', err => {
// 错误处理1
});
app.on('error', err => {
// 错误处理3
});
3.2 错误触发
在处理请求过程中,如果出错,就会进入promise实例的catch方法,在这个方法里调用context原型上的ctx.onerror方法
// application
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里面触发调用application实例emit方法,触发error事件,同时传参(err,ctx),对应2中,出现错误,无发响应,仍然传递当前请求上下文context实例。
// context.js
onerror(err) {
// 前置处理
// delegate
this.app.emit('error', err, this);
// 后置处理
}
fnMiddleware 是koa-compose处理app.middleware后的函数,返回promise实例
// koa-compose
function compose (middleware) {
if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
for (const fn of middleware) {
if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
}
/**
* @param {Object} context
* @return {Promise}
* @api public
*/
return function (context, next) {
// last called middleware #
let index = -1
return dispatch(0)
function dispatch (i) {
debugger
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i
let fn = middleware[i]
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}