Koa作为下一代Web开发框架,不仅让我们体验到了async/await语法带来同步方式书写异步代码的酸爽,而且本身简洁的特点,更加利于开发者结合业务本身进行扩展。
本文从以下几个方面分析其核心原理:
- 封装创建应用程序函数
- 扩展res和req
- 中间件原理
- 异常处理
一、封装创建应用程序函数
利用NodeJS可以很容易地编写一个简单的应用程序:
const http = require('http')
const server = http.createServer((req, res) => {
// 每一次请求处理的方法
console.log(req.url)
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('Hello NodeJS')
})
server.listen(8080)
注意:当浏览器发送请求时,会附带请求/favicon.ico,导致每一次请求触发两次。
而Koa在封装创建应用程序的方法中主要执行了以下流程:
- 组织中间件(监听请求之前)
- 生成context上下文对象
- 执行中间件
- 执行默认响应方法或者异常处理方法
// application.js
listen(...args) {
const server = http.createServer(this.callback());
return server.listen(...args);
}
callback() {
// 组织中间件 koa-compose
const fn = compose(this.middleware);
// 未监听异常处理,则采用默认的异常处理方法
if (!this.listenerCount('error')) this.on('error', this.onerror);
const handleRequest = (req, res) => {
// 生成context上下文对象
const ctx = this.createContext(req, res);
return this.handleRequest(ctx, fn);
};
return handleRequest;
}
handleRequest(ctx, fnMiddleware) {
const res = ctx.res;
// 默认状态码为404
res.statusCode = 404;
// 中间件执行完毕之后 采用默认的 错误 与 成功 的处理方法
const onerror = err => ctx.onerror(err);
const handleResponse = () => respond(ctx);
onFinished(res, onerror);
return fnMiddleware(ctx).then(handleResponse).catch(onerror);
}
二、扩展res和req
首先我们要知道NodeJS中的res和req是http.IncomingMessage和http.ServerResponse的实例,那么就可以在NodeJS中这样扩展req和res:
Object.defineProperties(http.IncomingMessage.prototype, {
query: {
get () {
return querystring.parse(url.parse(this.url).query)
}
}
})
Object.defineProperties(http.ServerRe