详解KOA2如何手写中间件(装饰器模式)

2020-06-17 06:53:22易采站长站整理

// 将 stat 和 access 转换成 Promise
const stat = promisify(fs.stat);
const access = promisify(fs.access)

module.exports = function (dir) {
return async (ctx, next) => {
// 将访问的路由处理成绝对路径,这里要使用 join 因为有可能是 /
let realPath = path.join(dir, ctx.path);

try {
// 获取 stat 对象
let statObj = await stat(realPath);

// 如果是文件,则设置文件类型并直接响应内容,否则当作文件夹寻找 index.html
if (statObj.isFile()) {
ctx.set("Content-Type", `${mime.getType()};charset=utf8`);
ctx.body = fs.createReadStream(realPath);
} else {
let filename = path.join(realPath, "index.html");

// 如果不存在该文件则执行 catch 中的 next 交给其他中间件处理
await access(filename);

// 存在设置文件类型并响应内容
ctx.set("Content-Type", "text/html;charset=utf8");
ctx.body = fs.createReadStream(filename);
}
} catch (e) {
await next();
}
}
}

上面的逻辑中需要检测路径是否存在,由于我们导出的函数都是 async 函数,所以我们将 stat 和 access 转化成了 Promise,并用 try…catch 进行捕获,在路径不合法时调用 next 交给其他中间件处理。

koa-router 中间件模拟

在 Express 框架中,路由是被内置在了框架内部,而 Koa 中没有内置,是使用 koa-router 中间件来实现的,使用前需要安装。


npm install koa koa-router

koa-router 功能非常强大,下面我们只是简单的使用,并且根据使用的功能进行模拟。

koa-router 的简单用法


const Koa = require("Koa");
const Router = require("koa-router");

const app = new Koa();
const router = new Router();

router.get("/panda", (ctx, next) => {
ctx.body = "panda";
});

router.get("/panda", (ctx, next) => {
ctx.body = "pandashen";
});

router.get("/shen", (ctx, next) => {
ctx.body = "shen";
})

// 调用路由中间件
app.use(router.routes());

app.listen(3000);

从上面看出 koa-router 导出的是一个类,使用时需要创建一个实例,并且调用实例的 routes 方法将该方法返回的 async 函数进行连接,但是在匹配路由的时候,会根据路由 get 方法中的路径进行匹配,并串行执行内部的回调函数,当所有回调函数执行完毕之后会执行整个 Koa 串行的 next ,原理同其他中间件,我下面来针对上面使用的功能简易实现。

文件:my-koa-router.js


// 控制每一个路由层的类
class Layer {
constructor(path, cb) {