- Koa与Node.js开发实战
- iKcamp
- 1984字
- 2020-08-27 23:29:52
2.3 Koa的中间件
中间件是Koa中一个非常重要的概念。Koa应用程序其实就是一个包含一组中间件函数的对象,而且有了async/await这种高级语法糖,使中间件写起来更加简单。
2.3.1 中间件概念
先来看下面这段代码:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_29.jpg?sign=1734384385-SRwQ14tWmZHquU92P3Y0zlGIor3ciY34-0-64d397eec3d58ac6a5430a2f16d3cbd8)
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_30.jpg?sign=1734384385-K5ropXiK7nT8jjoDHRxUollmhhpNHV48-0-bbac298e5a7e7ecdb83f12f4a72f7ef5)
上述代码是Koa应用程序的一个简单的“Hello World”示例,可以把其中打印日志的部分单独抽象成一个logger函数,代码如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_31.jpg?sign=1734384385-uvncFVz8WbHg86OL0YM4E5lFu6HyqzGK-0-a4a12027f665eeb1f3036b6c6253022d)
抽象出来的logger函数就是中间件,通过app.use()函数来加载中间件。
中间件函数是一个带有ctx和next两个参数的简单函数。ctx就是之前章节介绍的上下文,封装了Request和Response等对象;next用于把中间件的执行权交给下游的中间件。在next()之前使用await关键字是因为next()会返回一个Promise对象,而在当前中间件中位于next()之后的代码会暂停执行,直到最后一个中间件执行完毕后,再自下而上依次执行每个中间件中next()之后的代码,类似于一种先进后出的堆栈结构。这里用官方给出的 “洋葱模型”示意图(如图2.1所示)来解释中间件的执行顺序。
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_32.jpg?sign=1734384385-Ox4r26yrQCvtlQXiTMEgY2iNW0Gaqw8g-0-b04b4402b41e6687f521a9f89d620223)
图2.1 “洋葱模型”示意图
图2.1形象地展示了中间件的执行顺序。下面通过具体代码来演示中间件的执行,如下所示:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_33.jpg?sign=1734384385-yJL6AqWBax0MUIptKPwxsj0bDw0VBpU3-0-5fb8d30907b82ad07f97d0984c6d714e)
这段代码中有3个中间件,执行结果如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_34.jpg?sign=1734384385-VQN7MrRBXMW6exOyFXzHRlgLBgcohdjE-0-56b05107fe4b8125a4e2d06de0a57e0d)
如果想将多个中间件组合成一个单一的中间件,便于重用或导出,可以使用koa-compose,代码如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_35.jpg?sign=1734384385-ERdDbb14CLR0FTTSzj0D4OFHWcfQex7c-0-43dca4b4a59bd466e400a294d193b971)
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_36.jpg?sign=1734384385-kLuVXavF0wl3IcW9ZFkgM9cT1rXeipa6-0-baf47654684b5cbbdeb9eeaa9635e8f5)
Koa应用程序中的大部分功能都是通过中间件实现的,写好中间件也是学好Koa的必经之路。当然,也可以使用很多成熟的中间件模块来完善Koa应用,而且利用成熟的中间件模块也能大大提升开发效率。
2.3.2 实战演练:使用中间件获取响应时间(视频演示)
在实战项目中,经常需要记录服务器的响应时间,响应时间指的是从服务器接收到HTTP请求到最终返回给客户端之间所耗的时长。在Koa应用中,利用中间件机制可以很方便地实现这一功能,代码如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_37.jpg?sign=1734384385-KYhCSmZjoZ6qzbxJPeyg3kSAgQOwdzlW-0-a2e1fb6e69de843093f20c2df83e646a)
执行上述代码,控制台打印显示如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_38.jpg?sign=1734384385-4OsM2N7Y4WmBtwXlDywZo93MSeGfz4Tr-0-64de061af9a9fdd04ec990655544bd9c)
然后打开浏览器,访问http://localhost:3000,控制台显示内容更新如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_39.jpg?sign=1734384385-uAtKq6Vuvbc4eGHlgvfEqI7RjR30HVEN-0-84b5ce9d54505dfaa050a7e115f7e320)
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_40.jpg?sign=1734384385-vRNArNSR5NIXYwvAbCSmlMDbSL7WrWA2-0-dc6ef7e306f73e59d6d056e67fe7fa2c)
当服务器接收到HTTP请求后,会以“洋葱模型”的方式开始流转。先进入第1个中间件,在上述代码中,第1个中间件会记录下当前时间戳,然后将控制权向下传递,第2、第3个中间件进行相应的逻辑处理……最后再一层层地返回,直到返回给第1个中间件,再次记录下当前的时间戳。所记录的两次时间戳之间的差值,即为此次HTTP请求的响应时间。
细心的读者会发现,控制台打印了两条记录,这是因为访问http://localhost:3000后,DOM(Document Object Model,文档对象模型)结构在浏览器上进行渲染,会发起相应的静态资源文件的HTTP请求,/favicon.ico即为DOM渲染时默认自带的静态资源。
另外,读者可以思考一下,如果一个中间件没有调用await next(),又会发生什么情况呢?答案是:后面的中间件将不会被执行。读者可以自行验证一下。
本节在线视频地址为https://camp.qianduan.group/koa2/2/1/2,二维码:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_41.jpg?sign=1734384385-llLfLAIrBZXQe1aGRxt8BxvJB0roxflX-0-2d3bdb8177d3240e76f8723c7c3277bb)
2.3.3 常用Koa中间件介绍
利用成熟的中间件来构建Koa应用能大大提高开发效率。GitHub上的Koa社区提供了很多有用的中间件,读者可以访问https://github.com/koajs/koa/wiki进行搜索。本节主要介绍几个常用的中间件。
1.koa-bodyparser中间件
在2.2.2节中,有一个获取POST请求参数的例子,使用了Node.js的req对象监听data事件来获取,这种方法比较烦琐。koa-bodyparser中间件可以把POST请求的参数解析到ctx.request.body中。使用koa-bodyparser中间件首先需要安装,安装命令如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_42.jpg?sign=1734384385-aJdlp3Alwzp3Os7LURGEY9roZVOIJWi2-0-83ec9fdda25f1f3bde749e8f8ba23014)
接下来看一个使用koa-bodyparser中间件解析POST请求参数的实际例子,代码如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_43.jpg?sign=1734384385-qUMxGXHeGqPl1zJKAweYP3nM2BJvu7DA-0-6adb2c2baadc8874f3f8394c90159140)
运行上述代码,并在浏览器中访问http://localhost:3000/会看到一个登录表单,如图2.2所示。
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_44.jpg?sign=1734384385-gZBtIVj00fEHwxvzMsgLqzKbfCvUyRWD-0-fdae225b68e2781b372f78664dc0e6ca)
图2.2 登录表单
此处为了演示方便,未对用户名和密码做任何校验,所以可以在输入任意用户名和密码之后单击“submit”按钮,就会在页面上显示所填写的用户名和密码,如下所示:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_45.jpg?sign=1734384385-Zu0xdhJ8UQdIAagnEtnTcnaIrdMU0QDL-0-bfe968ebe01dc19d24c3cb83b16e96fa)
从这个结果可以知道,koa-bodyparser中间件最终解析出来的参数是一个对象。
2.koa-router中间件
上面登录表单的例子通过ctx.url判断路径,通过ctx.method判断请求的方法,这种手动判断路由的方式仍然比较麻烦,需要写很多的代码。如果借助koa-router中间件就能减少很多代码量。首先要安装koa-router,命令如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_46.jpg?sign=1734384385-LVUFIjqPkbBPT7V2y37iNus37j1OBnVX-0-cbfcd730fb8bc1ae05212e166ff00e87)
安装完成之后,用koa-router中间件改造之前的代码,代码如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_47.jpg?sign=1734384385-R5m07imzueH9jeSuHGv6a7jAEWouLaEk-0-52c966f11e22e5919d1bd3bed2c012b7)
经过改造之后的代码运行效果和之前是一样的,但是写法和代码都更精简,可读性也更高。(上述代码省略了绘制登录页和解析formData数据的部分,这部分代码没变,从上一个例子中复制过来即可)。
3.koa-static中间件与koa-views中间件
上面的例子简化了路由的写法,但是把HTML代码直接写在中间件中纯粹是为了演示方便。在实际开发中,不但会把HTML模板写在单独的文件中,还会引用单独的CSS样式及JavaScript文件,这时就需要用到koa-static和koa-views中间件。koa-static是专门用于加载静态资源的中间件,通过它可以为页面请求加载CSS、JavaScript等静态资源,而koa-views用于加载HTML模板文件。
下面使用koa-static和koa-views继续改写上面的例子,首先安装koa-static和koa-views,命令如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_48.jpg?sign=1734384385-xaRqR0MpZTbhb6VP7PASQ2LPRDx4WjYY-0-c6008aa4a9956190c941dd14d004defb)
安装完成之后来写核心代码,示例代码如下(完整代码请在GitHub上查看):
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_49.jpg?sign=1734384385-orcKo4egklduUh5AtzR2mqUfTgIJuZPj-0-0d964ea0a68f8b258d8a4d9cc2327599)
从上述代码中可以看出,之前直接写在中间件中的HTML代码被提取了出来,进一步简化了代码结构,并且还在HTML代码中引入了一个修改按钮样式的CSS文件和一个显示alert弹窗的JavaScript文件,运行结果如图2.3所示。
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_50.jpg?sign=1734384385-9OVnxKtL44fZNiCjq5DMmOCa4qJpUXcK-0-5b25210ab32a44e5f2f6ce55ea19215a)
图2.3 登录表单和弹窗
以上是Koa中最常用的4个中间件。通过不断加入新的中间件,app.js中的代码变得越来越简洁和健壮。善用成熟中间件来开发Koa应用是必修课。Koa还有很多其他常用的中间件,后面的章节会详细介绍其他常用中间件的使用方法,这里不再一一赘述。