如何从头实现一个node.js的koa框架

2020-06-17 06:09:13易采站长站整理

throw new Error('statusCode must be a number!');
}
this.res.statusCode = statusCode;
}
};

也很简单。status读写方法分别设置或读取this.res.statusCode。同样的,这个this.res是挂载的node原生response对象。而body读写方法分别设置、读取一个名为this._body的属性。这里设置body的时候并没有直接调用this.res.end来返回信息,这是考虑到koa当中我们可能会多次调用response的body方法覆盖性设置数据。真正的返回消息操作会在application.js中存在。

然后我们创建context.js文件,构造context对象的原型:


// context.js
module.exports = {
get query() {
return this.request.query;
},
get body() {
return this.response.body;
},
set body(data) {
this.response.body = data;
},
get status() {
return this.response.status;
},
set status(statusCode) {
this.response.status = statusCode;
}
};

可以看到主要是做一些常用方法的代理,通过context.query直接代理了context.request.query,context.body和context.status代理了context.response.body与context.response.status。而context.request,context.response则会在application.js中挂载。

由于context对象定义比较简单并且规范,当实现更多代理方法时候,这样一个一个通过声明的方式显然有点笨,js中,设置setter/getter,可以通过对象的__defineSetter__和__defineSetter__来实现。为此,我们精简了上面的context.js实现方法,精简版本如下:


let proto = {};
// 为proto名为property的属性设置setter
function delegateSet(property, name) {
proto.__defineSetter__(name, function (val) {
this[property][name] = val;
});
}
// 为proto名为property的属性设置getter
function delegateGet(property, name) {
proto.__defineGetter__(name, function () {
return this[property][name];
});
}
// 定义request中要代理的setter和getter
let requestSet = [];
let requestGet = ['query'];
// 定义response中要代理的setter和getter
let responseSet = ['body', 'status'];
let responseGet = responseSet;
requestSet.forEach(ele => {
delegateSet('request', ele);
});
requestGet.forEach(ele => {
delegateGet('request', ele);
});
responseSet.forEach(ele => {
delegateSet('response', ele);
});
responseGet.forEach(ele => {
delegateGet('response', ele);
});
module.exports = proto;

这样,当我们希望代理更多request和response方法的时候,可以直接向requestGet/requestSet/responseGet/responseSet数组中添加method的名称即可(前提是在request和response中实现了)。

最后让我们来修改application.js,基于刚才的3个对象原型来创建request, response, context对象: