深入剖析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接口设计原理,结合代码详细的讲解了洋葱模型的实现原理

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

相关推荐
Devil枫2 分钟前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
尚梦36 分钟前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子1 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山2 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
毕业设计制作和分享2 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
从兄3 小时前
vue 使用docx-preview 预览替换文档内的特定变量
javascript·vue.js·ecmascript
清灵xmf4 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
大佩梨4 小时前
VUE+Vite之环境文件配置及使用环境变量
前端
GDAL4 小时前
npm入门教程1:npm简介
前端·npm·node.js
小白白一枚1115 小时前
css实现div被图片撑开
前端·css