专栏首页前端有的玩浅析洋葱模型

浅析洋葱模型

如果你愿意一层一层 一层地剥开我的心 你会发现 你会讶异 你是我 最压抑 最深处的秘密 如果你愿意一层一层 一层地剥开我的心 你会鼻酸 你会流泪 只要你能 听到我 看到我的全心全意

前言

使用过koa的小伙伴们都应该对洋葱模型有所了解,koa的独特的中间件流程控制就是通过洋葱模型来实现的,那么洋葱模型是什么,又是如何实现的呢?

洋葱模型介绍

介绍

上图是洋葱模型比较经典的一个图,通过这个图可以看到,洋葱模型就像一个洋葱一个,是分成多层的,而一个请求进入的时候,会从外到内依次经过每一层,到最内侧之后又从内到外依次经过每一次,而我们就可以在这每一层上面做自己需要做的操作。

比如一个请求,在koa接收到请求的时候,首先需要鉴权,然后需要对请求参数解析等等,完成请求之后,需要处理异常,添加请求头等等操作,而这些操作就可以放到洋葱模型的每一层上面做处理。

示例代码

如下代码为koa的一段示例代码:

const Koa = require('koa');
const app = new Koa();

app.use(async (ctx, next) => {
  console.log(1);
  await next();
  console.log(2);
});

app.use(async (ctx, next) => {
  console.log(3);
  await next();
  console.log(4);
});
app.use(async (ctx, next) => {
  console.log(5);
  await next();
  console.log(6);
});

app.listen(8000);

执行上面的代码,会发现输出的数字顺序为1,3,5,6,4,2,与上面介绍的洋葱模型的执行顺序是一致的。

洋葱模型实现

首先我们先分析一下上面的代码app.use传入了一个异步的函数,而且app.use可以被使用多次,而这些函数在请求进入的时候会依次被调用,这是不是与发布订阅者模式是一致的,那首先我们来实现一个app.use

实现一个app.use

export interface Middleware {
  (...rest: any): Promise<any>;
}

export default class Onion {
  middlewares: Middleware[] = [];
  constructor(middlewares: Middleware[] = []) {
    this.middlewares = middlewares;
  }

  use(middleware: Middleware) {
    this.middlewares.push(middleware);
  }
}

上面代码我们定义了一个Onion类,通过这个类我们就可以将订阅函数进行收集,如下代码所示

const onion = new Onion()
onion.use(async(params, next)=> {
   console.log(1)
   await next()
   console.log(2)
})

发布者在收集完订阅函数后需要有触发的时机,这时候就需要再给Onion添加一个执行函数

完善Onion

有小伙伴想到发布订阅者的实现代码,可能就会想到这样做:

export default class Onion {
  middlewares: Middleware[] = [];
  constructor(middlewares: Middleware[] = []) {
    this.middlewares = middlewares;
  }

  use(middleware: Middleware) {
    this.middlewares.push(middleware);
  }

  execute(params: any) {
    this.middlewares.forEach(fn => {
          fn(params)
       })
  }
}

但是这样做的话,就无法满足洋葱模型的先入后出的顺序,那我们应该怎么做呢?

1.

定义 compose函数

function compose(middlewares: Array<Middleware>) {
if (!Array.isArray(middlewares)) {
 throw new Error('中间件必须是数组');
}
for (let i = 0; i < middlewares.length; i++) {
 if (typeof middlewares[i] !== 'function') {
   throw new Error('中间件的每一项都必须是函数');
 }
}

return (params: any) => {
 let index = 0;
 function dispatch(fn: Middleware | undefined) {
   if (!fn) {
     return Promise.resolve();
   }
   const next = () => dispatch(middlewares[++index]);
   return Promise.resolve(fn(params, next));
 }
 return dispatch(middlewares[index]);
};
}

2.

实现execute

export default class Onion {
middlewares: Middleware[] = [];
constructor(middlewares: Middleware[] = []) {
 this.middlewares = middlewares;
}

use(middleware: Middleware) {
 this.middlewares.push(middleware);
}

execute(params: any) {
 const fn = compose(this.middlewares);
 return fn(params);
}
}

通过定义componse函数,可以将中间件函数依次按照顺序来执行。

const onion = new Onion();
onion.use(async (params: any, next: Middleware) => {
 console.log(1);
 await next();
 console.log(2);
});

onion.use(async (params: any, next: Middleware) => {
 console.log(3);
 await next();
 console.log(4);
});

onion.use(async (params: any, next: Middleware) => {
 console.log(5);
 await next();
 console.log(6);
});

onion.execute({});

这样我们就实现了一个简易版的洋葱模型。

本文分享自微信公众号 - 前端有的玩(gh_918bae0a9616),作者:前端进击者

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-06-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 学习 koa 源码的整体架构,浅析koa洋葱模型原理和co原理

    感兴趣的读者可以点击阅读。 其他源码计划中的有:express、vue-rotuer、redux、 react-redux 等源码,不知何时能写完(哭泣),欢...

    若川
  • 吃透洋葱模型

    作者:掘金@苏里 https://juejin.im/post/6844904025767280648

    zz_jesse
  • koa源码解析,理解洋葱模型

    之前,我一直在使用express做简单的后台server,写一些api,给自己做的前端来提供服务,觉着吧挺好用的,虽然koa也出来挺久的,但是我一直没有更换过,...

    brzhang
  • 读 koa2 源码后的一些思考与实践

    优点这个东西,我直接说它多好,你可能又不开心,但是我们可以对比哦!这里我只说它对比原生的 Node.js开启 http 服务 带来了哪些优点!

    coder_koala
  • 如何更好地理解中间件和洋葱模型

    相信用过 Koa、Redux 或 Express 的小伙伴对中间件都不会陌生,特别是在学习 Koa 的过程中,还会接触到 “洋葱模型”。

    前端森林
  • 以小白的角度解读Koa源码

    使用Koa已有一段时间,为什么会从Express转向Koa呢,那还是得从Express上说起。对于服务端的Web框架来说,Express更为贴近「Web Fra...

    JowayYoung
  • 主机安全——洋葱Webshell检测实践与思考

    Webshell是网站入侵的常用后门,利用Webshell可以在Web服务器上执行系统命令、窃取数据等恶意操作,危害极大。Webshell因其隐秘性、基于脚本、...

    腾讯安全应急响应中心
  • 洋葱海外仓融资2亿元 官网启用msyc.cc域名

    洋葱集团旗下跨境社交零售平台「洋葱海外仓」近日宣布,已于 2017 年第三季度完成 2 亿元 C 轮融资,赛富基金领投,原有股东跟投。此前,洋葱海外...

    躲在树上的域小名
  • 腾讯自研HIDS「洋葱」后台上云架构演进实践

    “洋葱”系统是腾讯自研的主机入侵检测系统(HIDS),能够实时采集服务器上的各种行为并进行实时关联分析和落地存储,承载公司所有的服务器、虚拟机和容器的入侵防护、...

    腾讯安全应急响应中心
  • AI如何更好地协助人类,我们从美食游戏中得到了一些启发

    然而AI的陪练系统通常会根据其进步而增加训练难度。在自我博弈的训练中,有时,AI要学会左右互搏,有时,AI要和其他AI一起玩以方便各自提升。

    大数据文摘
  • 基于威胁情报周期模型的APT木马剖析

    近日,腾讯服务器安全系统“洋葱”协助部署于公有云的某合作方捕获到一起APT事件,目前已处置完毕。处置过程中捕获木马样本一枚,该样本中包含了大量隐匿攻击手法,“洋...

    腾讯安全应急响应中心
  • 【安全通知】PyPI 官方仓库遭遇covd恶意包投毒

    近日,腾讯洋葱反入侵系统检测发现 PyPI官方仓库被恶意上传了covd 钓鱼包,并通知官方仓库下架处理。由于国内开源镜像站均同步于PyPI官方仓库,所以该问题不...

    腾讯安全应急响应中心
  • koa与express的中间件机制揭秘

    TJ大神开发完express和koa后毅然决然的离开了nodejs转向了go,但这两个web开发框架依然是用nodejs做web开发应用最多的。

    挥刀北上
  • ​8 月直播课抢先看 | 代码质量实战 + 微服务项目实战课程报名中

    CODING DevOps 8 月直播课来了~!这次 CODING 为大家带来了两场系列直播课,每系列包含 3 节课程,循序渐进,由浅入深,争取在每晚 1 小时...

    CODING
  • JavaScript 设计模式学习第二十九篇- 中间件

    (Middleware),又称中介层,是提供系统软件和应用软件之间连接的软件,以便于软件各部件之间的沟通,特别是应用软件对于系统软件的集中的逻辑。中间件在企业架...

    越陌度阡
  • 【安全通知】知名端口转发工具rinetd遭高仿投毒

    近日,腾讯洋葱反入侵系统检测发现了一起仿造开源软件官方站点的钓鱼事件,并已与官方作者取得联系。事实上该开源软件目前仅在github发布,目前正在尝试推动该站点下...

    腾讯安全应急响应中心
  • 披荆斩棘:论百万级服务器反入侵场景的混沌工程实践

    在繁杂的业务和网络环境下,在公司百万级服务器面前,要做到入侵发生时的及时检测,那么反入侵系统的有效性,即系统质量,是至关重要的。

    腾讯技术工程官方号
  • 披荆斩棘:论百万级服务器反入侵场景的混沌工程实践

    在繁杂的业务和网络环境下,在公司百万级服务器面前,要做到入侵发生时的及时检测,那么反入侵系统的有效性,即系统质量,是至关重要的。

    腾讯安全应急响应中心
  • 暗网Tor路由器用户被坑,最新研究: 原来比特币交易可以泄露他们的身份……

    比特币并不是一个完全匿名的支付网络。然而,实际上,有很多人(即使是最注重隐私的人)似乎都忘记了这一点。

    区块链大本营

扫码关注云+社区

领取腾讯云代金券