模拟实现玩具版 koa

it2022-05-05  150

 

最近读了 koa2 的源码,理清楚了架构设计与用到的第三方库。本系列将分为 3 篇,分别介绍 koa 的架构设计和 3 个核心库,最终会手动实现一个简易的 koa。这是系列第 3 篇,模拟实现玩具版 koa。

源码和测试代码放在了:dongyuanxin/simple-koa

#准备

设计思想和第三方库原理都在前 2 篇详细说明了。这篇主要目的是做一个验证检验,在语法使用 ES6/7 的语法。

在开始前,安装一下需要用到的库:

npm install --save koa-compose koa-convert is-generator-function

1

#测试文件

为了说明效果,先按照正常使用 koa 的逻辑编写了测试文件。当启动它的时候,它的预期行为是:

监听 3000 端口加载中间件浏览器访问localhost:3000,屏幕打印hello服务器的控制台依次输出:1inner => 2innter => 2outer => 1outer

代码如下:

const Koa = require("./lib/application"); const server = new Koa(); async function middleware1(ctx, next) { console.log("1 inner"); await next(); console.log("1 outer"); } async function middleware2(ctx, next) { ctx.res.body = "hello"; console.log("2 inner"); await next(); console.log("2 outer"); } server.use(middleware1); server.use(middleware2); server.listen(3000);

 

#玩具 koa

只准备了一个文件,跑通上面的逻辑即可。文件是 lib/application.js 。

#构造函数

首先对外暴露的就是一个继承 Emitter 的 Application 类。整体框架如下:

const http = require("http"); const Emitter = require("events"); const compose = require("koa-compose"); module.exports = class Application extends Emitter { constructor() { super(); this.middleware = []; // 中间件 this.context = {}; // 上下文 this.request = {}; // 请求信息 this.response = {}; // 返回信息 } listen(...args) {} use(fn) {} callback() {} handleRequest(ctx, fnMiddleware) {} createContext(req, res) {} onerror(error) { console.log(`error occurs: ${error.message}`); } };

 

继承 Emitter 事件类,是为了方便监听和处理报错。

#use

将外面传入的中间件保存起来:

use (fn) { this.middleware.push(fn) return this }

 

#createContext

主要用于创建上下文。外面可以通过访问 ctx 上的 req/res 拿到请求或者返回信息。

createContext (req, res) { const context = Object.create(this.context) context.request = Object.create(this.request) context.response = Object.create(this.response) context.req = req context.res = res context.app = this context.state = {} return context }

 

#listen 和 callback

监听端口,启动服务器:

listen (...args) { const server = http.createServer(this.callback()) return server.listen(...args) }, callback () { const fn = compose(this.middleware) this.on('error', this.onerror) return (req, res) => { const ctx = this.createContext(req, res) return this.handleRequest(ctx, fn) } }

 

#handleRequest

在 callback 方法中真是返回的内容,它的作用就是:处理请求,并且返回给客户端。

 

 

handleRequest(ctx, fnMiddleware) { const res = ctx.res // res.statusCode = 404 const handleResponse = () => { res.end(res.body) } return fnMiddleware(ctx) .then(handleResponse) .catch(this.onerror) }

转自https://xin-tan.com/passages/2019-06-21-deep-in-koa-3/#玩具-koa 


最新回复(0)