什么是中间件

中间件是框架额扩展机制,主要用于 HTTP 请求过程。在单一请求响应过程中加入中间件,可以更好地应对负责的业务逻辑。

从代码层面看,在 App 和 serverListen 之间的代码都是中间件,中间件执行的顺序和挂载的顺序有关,越靠前的中间件越早执行。下面是中间件执行的经典洋葱图。


image

请求到达服务器后,依次经过各个中间件,直至被响应。

Koa v1

ES6 中一边循环一边计算的计算机制成为生成器,其最大的特点就是可以通过 yield 关键字交出函数的执行权(暂停执行),即可以让一个函数异步执行完后,再继续执行当前流程。
Koa v1 是一个探索版本,实在 Node.js 最开始支持 ES6 Generator 特性时使用 Generator/yield 做出的大胆尝试。
在 app.js 文件里,代码如下:

const koa = require('koa')
const app = koa()

// 日志
app.use(function * log(next) {
  const start = new Date()
  
  yield next
  const ms = new Date() - start
  console.log(ms) 
})

// 响应
app.use(function *res(next) {
  this.body = 'hello world'
})

app.listen(3000)

很明显,在执行了 yield next 以后,才会执行下一个中间件,即 res 中间件,于是代码执行方式就借助 Generator 转变成了顺序执行,这就是 Koa v1 带来的最直观的变化。
另外,ES6 Generator 中间件内部使用 this 作为隐式的上下文,这在 js 中非常容易出错,这算是 Koa v1 的小小瑕疵。

Koa v2

Koa v2 是一个更成熟的 Web 框架,是由 Koa v1 演进而成的。Koa v2 最重要的特性就是支持 async 函数,并且同时支持如下 3 种不同类型函数的中间件。

  1. 通用函数中间件
    下面是通用函数中间件的示例
const Koa = require('koa')
const app = new Koa()

// 日志
app.use((ctx, next) =>{
  const start = new Date
  return next().then( () => {
    const ms = new Date - start
    console.log(ms)
  } )
})

// 响应
app.use(ctx = > {
  ctx.body = 'hello world'
})

(ctx, next) => {} 和 Koa v1 中间件的 function *(next) {} 相比,区别如下。

  • 写法差异:Koa v2 中间件是普通的函数,不是 Generator 函数。
  • 参数差异:Koa v1 中间件的参数有 1 个,而 Koa v2 中间件的参数有 2 个,这主要是因为上下文 ctx 在 Koa v2 被显式的声明了。可以理解,Koa v1 中间件里的 this 就是 Koa v2 中间件里的 ctx,它们的 API 是完全一样的。
  • 异步技术差异:Koa v2 中间件内部使用 Promise 进行异步处理,而 Koa v1 中间件内部使用 Generator。

  1. 生成器函数中间件
    Koa 的设计初衷是便于开发者基于 ES6 Generator 来构建更好的控制流程,所以 Koa v2 也支持 ES6 Generator,但和 Koa v1 稍有不同。
const Koa = require('koa')
const app = new Koa()

// 日志
app.use(co.warp()function*(ctx, next) {
  const start = new Date
  yield next()
  const ms = new Date - start
  console.log(ms)
})

// 响应
app.use(ctx => {
  ctx.body = 'hello world'
})

app.listen(3000)

将以上代码与 Koa v1 代码对比,主要区别如下:

  • Koa v2 生成器函数中间件被 co.warp 包裹并被转换成 function*(){}。
  • Koa v2 生成器函数中间件的参数多了 ctx,和上面的通用函数中间件一样,上下文 ctx 被显式的声明了,统一了写法。
  • 从 Koa v2 生成器函数中间件跳转到下一个中间件是通过 yield next() 函数实现的,而不是 Koa v1 中用的 yield next
  1. async 函数中间件
    async 函数的优势如下:
  • 语义更好
  • 无须执行器,比 Generator + co 的解决方案好很多。
  • await 可以无缝调用异步 Promise 方法,更好的向后兼容
    下面给出 async 函数中间件的用法:
const Koa = require('koa')
const app = new Koa()

// 日志
app.use(async (ctx, next) => {
  const start = new Date
  await next()
  const ms = new Date - start
  console.log(ms)
})

// 响应
app.use(ctx => {
  ctx.body = 'hello world'
})

app.listen(3000)

以上代码的要点如下:

  • async 函数除了多一个 async 关键子之外,和普通函数无异,同样支持箭头函数。(Genertaor 是不支持箭头函数的)
  • 与 async 函数搭配的 await 关键字可以对接 Promise 方法,尽管他没有 yield的 yieldable那么强大。
  • Koa v2 的 async 函数中间件跳转到下一个中间件时需要使用 await next(), 和普通函数中间件里的 return next() 类似。

总结,从形式上看,async 函数中间件无疑是所有中间件中最耀眼的那个,它语义清楚,结合 await 关键字可以非常好的整合 Promise,还能更好地兼容各种已有代码。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • Koa 必须使用 7.6 以上的版本。如果你的版本低于这个要求,就要先升级 Node。 基本用法 Koa 提供一个...
    Gukson666阅读 2,442评论 0 1
  • 什么是中间件简单说,中间件(middleware)就是处理HTTP请求的函数。它最大的特点就是,一个中间件处理完,...
    Kason晨阅读 188评论 0 0
  • 一、为什么要中间件 计 算机技术迅速发展。从硬件技术看,CPU速度越来越高,处理能力越来越强;从软件技术看,应用程...
    唐怀瑟_阅读 3,200评论 0 16
  • 什么是中间件? 比如流水线工作 每个工人做的事情都很唯一 如果要真正生产出一个手机 要经过每一个工人的处理 才能...
    没有刘海儿阅读 1,493评论 0 3
  • 近几年爸爸的身体不怎么好,因为远嫁,加上孩子上学,还有杂七杂八的生活琐事,每年很少回去;如不是爸爸最近身体不好,估...
    乐乐乐安阅读 108评论 0 0