前言
Express 和 Koa 是目前最主流的基于 node 的 web 开发框架, 他们的开发者是同一班人马貌似现在 Koa 更加流行, 但是仍然有大量的项目在使用 Express, 所以我想通过这篇文章说说 Express 中间件的原理
中间件的功能和分类
中间件的本质就是一个函数, 在收到请求和返回相应的过程中做一些我们想做的事情 Express 文档中对它的作用是这么描述的:
执行任何代码
修改请求和响应对象
终结请求 - 响应循环
调用堆栈中的下一个中间件
分类
Express 文档中把他们分为了五类, 但是他们的原理相同, 只是用法不同:
应用级中间件
路由级中间件
错误处理中间件
内置中间件
第三方中间件
中间件的原理
首先我们看看中间件的用法:
- var express = require('express')
- var app = express();
- app.use('/user', function (req, res, next) {
- //TODO
- next();
- });
- app.listen(8080)
接下来我们对比看一下下源码:
与中间件有关的有三部分:
express.js 继承 application.js 并对外暴露接口
application.js 挂载了所有核心方法
router 文件夹处理路由逻辑
先看 express.js 的代码:
这部分代码中最重要的是红色方框部分, mixin 是一个第三方库可以简单理解为继承 (实际上它不是继承而是混合)
接下来我们看 application.js:
我把文件下载下来并且删去了注释, 通过这张图我们可以看出这个文件的作用是挂载了所有的方法 (包括 use 等关键 api)
这里面比较重要的是 use 方法, 它的作用就是把我们用 app.use 注册的所有中间件和路由方法交给 Router 类来处理
那我们再看看 router 文件夹类的结构:
index.js 是入口文件, 处理所有的路由;
layer.js 中声明了 Layer 类, 处理每一层路由中间件或者每一个子中间件;
router.js 中声明了 Router 类, 处理每一个子路由
这里面有一个子中间件的概念, 对应 Exprees 文档中有这一句话:
另外, 你还可以同时装载一系列中间件函数, 从而在一个挂载点上创建一个子中间件栈
这句话的意思是说我们可以把代码写成下面这种形式:
- app.use('/user1', function fn1(req, res, next) {
- // TODO
- next();
- }, function fn2(req, res, next) {
- //TODO
- next();
- });
- app.use('/user2', function fn3(req, res, next) {
- // TODO
- next();
- }, function fn4(req, res, next) {
- //TODO
- next();
- });
上面的代码给 user1 和 user2 分别创建了一个子中间件栈这种语法的实现就是靠 Layer 类实现的
画一张图来解释上面的代码:
解释一下上面的代码和图:
我们写了两个路由 / user1 和 / user2, 每个路由给了两个处理函数对于这段代码, Express 是这样处理的:
在 index.js 文件中, 定义了一个 stack 数组, 接下来会创建两个 Layer 放到这个 stack 中
route.js 模块会给 / user1 再创建一个 stack 和 fn1fn2 两个 Layer
/user2 同 / user1
最后, Express 会从上往下执行每个 Layer 里的函数, 对应到图上就是从上至下从左至右的依次执行, 顺序为 fn1fn2fn3fn4
最后
以上就是 Express 中间件的简单原理, 白话较多, 如果写的不准确的地方, 希望大家批评指正
参考资料
Express 官网
Express 的 github 仓库地址
来源: https://juejin.im/post/5aa345116fb9a028e52d7217