首相,讲解一下koa的大致思路,用户实例化Koa构造函数,通过调用实例化对象上的use方法,获取到url地址等属性,也可以通过body给客户端响应内容,这些属性都是集成在ctx对象上。用户通过调用listen方法开启服务配置端口号。我们来看一下koa到底是怎么配置一个服务的。
const Koa = require("./koa/application.js"); // 自定koa函数
const app = new Koa();
app.use(async function(ctx,next){
console.log(ctx.url);
console.log(ctx.request.path);
await next();
ctx.body = "hello world";
})
app.use(async function(ctx,next){
await log(); // 异步promise对象
await next();
console.log(3333);
})
app.use(function(ctx,next){
console.log(4444);
next();
console.log(5555);
})
app.listen(8888,function(){
console.log("localhost:8888")
})
准备主体文件application.js
1、koa是通过package.json设置默认引用主体文件,主体文件会准备一个Koa构造函数,函数内准备一个存储器,当用户执行use时,用来存储use里面的回调函数。当用户执行listen的时候,通过http模块开启服务。
const http = require("http");
function Koa(){
this.callback = []
}
Koa.prototype.use = function(fn){
this.callback.push(fn);
}
Koa.prototype.listen = function(){
const server = http.createServer(this.server.bind(this));
server.listen(...arguments);
}
2、通过server函数集成ctx对象,http模块会默认传递req和res对象,我们需要把req/res集成到ctx对象上,这里注意的是ctx对象的req/res是等于http服务上的req/res。还需要准备三个js文件用来存储ctx/request/response这三个对象。
const context = require("./context.js");
const request = require("./request.js");
const response = require("./response.js");
Koa.prototype.getCtx = function(req,res){
let ctx = Object.create(context);
ctx.request = Object.create(request);
ctx.response = Object.create(response);
ctx.req = ctx.request.req = req;
ctx.res = ctx.response.res = res;
return ctx;
}
Koa.prototype.server = async function(req,res){
let ctx = this.getCtx(req,res);
}
3、处理用户调用use储存在callback的回调函数,默认会执行第一次回调函数,当用户执行next的时候,我们需要准备一个执行机传递给next作为回调函数的参数,执行机的内容也就是执行下一个use。
Koa.prototype.compose = function(ctx,callback){
function dispath(index){
if(index == callback.length) return;
let exe = callback[index];
return Promise.resolve(exe(ctx,()=>dispath(index+1)));
}
return dispath(0)
}
Koa.prototype.server = async function(req,res){
........
await this.compose(ctx,this.callback);
}
4、监听ctx.body里面的内容,当用户body有设置值的时候,通过end把值响应给客户端,没有值需要给个默认的code和值。
Koa.prototype.server = async function(req,res){
........
let content = "";
if(ctx.body){
content = ctx.body;
}else{
res.statusCode = 404;
content = "Not Found";
}
res.end(content);
}
准备request.js文件作为ctx.request对象进行拦截
const url = require("url");
let request = {
get url(){
return this.req.url;
},
get path(){
return url.parse(this.req.url).pathname;
}
}
module.exports = request;
准备response.js文件作为ctx.response对象进行拦截
let response = {
get body(){
return this._body;
},
set body(newValue){
this._body = newValue;
}
}
module.exports = response;
准备context.js文件作为ctx对象进行拦截
let context = {}
function intercept(property,name){
Object.defineProperty(context,name,{
get(){
return this[property][name];
},
set(newValue){
this[property][name] = newValue;
}
})
}
intercept("request","url");
intercept("request","path");
intercept("response","body");
module.exports = context;
项目案例