深入剖析Koa接口封装原理,洋葱模型?递归调用?

前言

本文深入剖析Koa接口设计原理

讲解一下koa在封装接口时使用的洋葱模型以及洋葱模型实现原理递归调用

koa中间件式编程

Koa 中间件是一系列的函数,通过传递给 app.use() 的方式注册到应用程序中

每个中间件函数都会在请求或响应的某个阶段被执行,从而实现了对请求/响应生命周期的控制和扩展

我们看以下的代码

js 复制代码
const Koa = require("koa");

const app = new Koa();
const main = (ctx) => {
  console.log(ctx.url);
  if (ctx.url === "/") {
    ctx.response.type = "html";
    ctx.response.body = "首页";
  } else if (ctx.url === "/about") {
    ctx.response.type = "html";
    ctx.response.body = "关于";
  } else {
    ctx.response.type = "html";
    ctx.response.body = "404";
  }
};

app.use(main);

app.listen(3000, () => {
  console.log("http://localhost:3000");
});
  1. 引入 Koa 框架并创建一个新的 Koa 应用实例 app

  2. 定义了一个名为 main 的函数,它是一个中间件函数。这个函数接收 ctx 对象作为参数,ctx 对象包含了当前请求的上下文信息。

  3. main 函数中,根据不同的 URL 路径设置响应的类型和内容:

    • 如果访问根路径 /,返回 "首页" 字符串。
    • 如果访问 /about 路径,返回 "关于" 字符串。
    • 对于其他路径,返回 "404" 字符串。
  4. 使用 app.use(main)main 函数注册为中间件。这样,每次收到 HTTP 请求时,都会执行 main 函数来处理请求。

  5. 最后,调用 app.listen(3000, () => {...}) 在 3000 端口启动服务器,并在控制台输出 http://localhost:3000 提示访问地址。

可以看到在这段代码中main就相当于一个中间件,被koa框架给use了

文件响应

请求下载文件

  • 使用 fs.readFileSync("./template.html") 同步地读取 template.html 文件的内容,并将其赋值给 context 变量。
  • 打印 context 的内容到控制台。
  • context 的内容赋值给 ctx.body,将该内容作为响应返回给客户端
js 复制代码
const Koa = require("koa");
const fs = require("fs");

const app = new Koa();
const main = (ctx) => {
 
    const context = fs.readFileSync("./template.html");
    console.log(context);
    ctx.body = context;


};

app.use(main);

app.listen(3000, () => {
  console.log("http://localhost:3000");
});

这样实现的效果就是当我们去请求这个路径的时候会触发文件的下载

我们的文件内容为

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2>hello world</h2>
    <h3>hello koa</h3>
</body>
</html>

可以看到打开下载的文件其内容就是这个

请求文件直接显示

如果我们希望使用html的方式去显示这段内容,我们需要再请求头的type字段指明一下,添加以下代码即可

js 复制代码
ctx.response.type = "html";

可以看到html被正确的显示出来了

koa-route 优雅的接口书写

前面提到的接口的书写方式并不是很优雅,通过不断地if-else去创建接口很不优雅

koa-route就将这个给进一步封装了,使得其书写的方式更加的优雅了

接下来我们引入koa-route

js 复制代码
npm i koa-route

引入到项目中使用

js 复制代码
const Koa = require("koa");
const Router = require("koa-route");

const app = new Koa();
const main = (ctx, next) => {
  ctx.response.type = "html";
  ctx.body = "<h2>首页</h2>";
  next();
};

const about = (ctx) => {
  ctx.response.type = "html";
  ctx.body = "<h2>关于</h2>";
};

app.use(Router.get("/", main));
app.use(Router.get("/about", about));

app.listen(3000, () => {
  console.log("http://localhost:3000");
});

可以看到这段代码将一个一个接口通过函数的方式进行了封装,并交给了koa

这样写代码就优雅了许多

这里面就涉及到了我们接下来要说的洋葱模型了

洋葱模型

为什么叫做洋葱模型呢?听我细细分析

我们首先看以下代码,猜测一下它的执行结果

js 复制代码
const Koa = require("koa");

const app = new Koa();

// 递归调用
// 洋葱模型
// 中间件
const one = (ctx, next) => {
  console.log(1);
  next();
  console.log(2);
};

const twe = (ctx, next) => {
  console.log(3);
  next();
  console.log(4);
};

const three = (ctx, next) => {
  console.log(5);
  console.log(6);
};

app.use(one);
app.use(twe);
app.use(three);

app.listen(3000, () => {
  console.log("http://localhost:3000");
});

执行结果为 135642

这就好像一个洋葱,每个中间件函数都可以在调用 next() 之前和之后执行一些操作,形成类似洋葱的结构

形成这个模型的原因就是因为它是用递归调用的

当执行到 one 中间件函数时:

  1. 首先打印出 "1"。
  2. 然后调用 next() 将控制权传递给下一个中间件 twe
  3. twe 中间件函数执行完毕并调用 next() 后,控制权又回到了 one 中间件函数。
  4. 此时 one 中间件函数继续执行,打印出 "2"。

当执行到 twe 中间件函数时:

  1. 首先打印出 "3"。
  2. 然后调用 next() 将控制权传递给下一个中间件 three
  3. three 中间件函数执行完毕后,控制权又回到了 twe 中间件函数。
  4. 此时 twe 中间件函数继续执行,打印出 "4"。

所以,整个执行顺序如下:

  1. 执行 one 中间件函数,打印 "1"。
  2. 执行 twe 中间件函数,打印 "3"。
  3. 执行 three 中间件函数,打印 "5" 和 "6"。
  4. 执行 twe 中间件函数,打印 "4"。
  5. 执行 one 中间件函数,打印 "2"。

总结

本文深入剖析Koa接口设计原理,结合代码详细的讲解了洋葱模型的实现原理

希望看到这里的你能够有所收获!!!

相关推荐
布列瑟农的星空14 分钟前
rsbuild mock 插件开发指南
前端
用泥种荷花29 分钟前
【LangChain.js学习】 文档加载(Loader)与文本分割全解析
前端
cxxcode1 小时前
Vite 热更新(HMR)原理详解
前端
HelloReader1 小时前
Tauri 架构从“WebView + Rust”到完整工具链与生态
前端
UIUV1 小时前
node:child_process spawn 模块学习笔记
javascript·后端·node.js
Bigger1 小时前
告别版本焦虑:如何为 Hugo 项目定制专属构建环境
前端·架构·go
烛阴2 小时前
Three.js 零基础入门:手把手打造交互式 3D 几何体展示系统
javascript·webgl·three.js
颜酱3 小时前
单调栈:从模板到实战
javascript·后端·算法
代码匠心3 小时前
AI 自动编程:一句话设计高颜值博客
前端·ai·ai编程·claude
_AaronWong4 小时前
Electron 实现仿豆包划词取词功能:从 AI 生成到落地踩坑记
前端·javascript·vue.js