0%

express 中间件原理及实现

中间件的使用案例

1
2
3
4
5
6
const express = require('express');
const app = express();

app.use(function(req,res,next) {
next()
})

以上是最简单的例子。一个中间件就是一个函数,参数为req,res,next。在这个函数中,必须执行next函数或者发送响应,否者服务会被挂起,客户端会一直处于等待。

为什么要使用中间件

在中间件中可以处理req、res对象,给他们增加新的方法和属性,供下一个中间件调用,还可以通过next控制权限,提前中断后续中间件的调用。这样的话就可以将应用的功能拆分出来,实现功能的解耦。

中间件的原理是什么

connect内部维护了一个数组,执行app.use会往这个数组中增加一个中间件。当接收到一个请求时,如果中间件执行了next(),会依次往下执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
var http = require('http');

function express() {
var stack = []; // 中间件函数数组

function app(req, res) {
var i = 0;

function next() {
var handler = stack[i++];

if (!handler) {
return;
}
// 中间件函数调用,如果调用了next,相当于递归调用,下一个中间件函数就会执行
handler(req, res, next);

}

next();
}

// 增加中间件
app.use = function (middleware) {
stack.push(middleware);
};

return app;
}

var app = express();
http.createServer(app).listen(3000);

app.use(function (req, res, next) {
console.log('start1');
next();
console.log('next1');
});
app.use(function (req, res, next) {
console.log('start2');
next();
console.log('next2');
});
app.use(function (req, res) {
console.log('start3');
});
// 打印结果
// start1
// start2
// start3
// next2
// next1

注意,这里用了两个闭包,一个维护stack中间件数组,一个维护中间件函数下标i
前面看的是express3,后面看了express4源码。

express 不使用 connect 管理中间件了。
一个中间件包含一个 route 属性,当一个请求进来时,循环所有的中间件,next(router) 提前退出,没有定义路由的提前退出,路径不匹配的提前退出。

Routestack 数组,里面都是 Layer 实例,在解析中间件时,Layer 将路由路径转化为正则表达式,并将参数解析,放到他自己本身的属性上,在循环中间件时,req 对象上合并 Layerparams 属性。在Route.process_params回调中调用 Layer.handle_request 执行中间件函数。