于此同时,回顾koa框架,我们知道在错误发生的时候,app对象可以通过app.on(‘error’, callback)订阅错误事件,这有助于我们几种处理错误,比如打印日志之类的操作。为此,我们也要对Application对象进行改造,让其继承nodejs中的events对象,然后在onerror方法中emit错误事件。改造后的application.js如下:
/**
* @file simpleKoa application对象
*/
let EventEmitter = require('events');
let http = require('http');
let context = require('./context');
let request = require('./request');
let response = require('./response');
class Application extends EventEmitter {
/**
* 构造函数
*/
constructor() {
super();
this.middlewares = [];
this.context = context;
this.request = request;
this.response = response;
}
// ...
/**
* 获取http server所需的callback函数
* @return {Function} fn
*/
callback() {
return (req, res) => {
let ctx = this.createContext(req, res);
let respond = () => this.responseBody(ctx);
let onerror = (err) => this.onerror(err, ctx);
let fn = this.compose();
// 在这里catch异常,调用onerror方法处理异常
return fn(ctx).then(respond).catch(onerror);
};
}
// ...
/**
* 错误处理
* @param {Object} err Error对象
* @param {Object} ctx ctx实例
*/
onerror(err, ctx) {
if (err.code === 'ENOENT') {
ctx.status = 404;
}
else {
ctx.status = 500;
}
let msg = err.message || 'Internal error';
ctx.res.end(msg);
// 触发error事件
this.emit('error', err);
}
}
module.exports = Application;可以看到,onerror方法的对异常的处理主要是获取异常状态码,当err.code为’ENOENT’的时候,返回的消息头设置为404,否则默认设置为500,然后消息体设置为err.message,如果异常中message属性为空,则默认消息体设置为’Internal error’。此后调用ctx.res.end返回消息,这样就能保证即使异常情况下,客户端也能收到返回值。最后通过this.emit出发error事件。
然后我们写一个example来验证错误处理:
let simpleKoa = require('./application');
let app = new simpleKoa();
app.use(async ctx => {
throw new Error('ooops');
});
app.on('error', (err) => {
console.log(err.stack);
});
app.listen(3000, () => {
console.log('listening on 3000');
});浏览器访问’localhost:3000’的时候,得到返回’ooops’,同时http状态码为500 。同时app.on(‘error’)订阅到了异常事件,在回调函数中打印出了错误栈信息。
关于错误处理,这里多说一点。虽然koa中内置了错误处理机制,但是实际业务开发中,我们往往希望能够自定义错误处理方式,这个时候,比较好的办法是在最开头增加一个错误捕获中间件,然后根据错误进行定制化的处理,比如:









