Express中间件原理及手动封装

“ 在项目中使用node的时候,我们往往不会使用原生的,而是使用Express框架来更快的解决服务端的问题。其中我们最长听见和使用的便是中间件,今天就来带领大家更进一步的了解Express的中间件的原理,以及如何实现。”

PS:测试接口可以使用Postman工具。

1. 什么是中间件

简单的一句话概括中间件其实就是函数在响应发送之前对请求进行一些操作

引用网上说:一个请求发送到服务器后,它的生命周期是先收到request请求,然后服务器进行处理,处理完之后发送response响应回去。在这里服务器处理的过程就复杂多了,当业务逻辑多且复杂时,为了明确和维护,因此可以拆分,拆分的每一个部分就是一个中间件。举几个例子来形容中间件是什么:

(1)你可以将中间件想象成自来水处理和净化的过程,其中对自来水进行加工的步骤就是一个个的中间件组成的;

(2)实验室中的漏斗,经过过滤等步骤,在这里的步骤也是一个个的中间件;
(3)食品加工厂中加工的每一个步骤就是一个个的中间件,将原料经过一系列的加工最后包装然后出厂;

在Express中,中间件机制使得我们的开发更加的高效便捷、易于维护、提高复用性、逻辑处理更加清晰。比如在公司业务中,需要在接口中添加监控和埋点,此时如果我没有使用中间件的话,那么需要每次都在请求的接口中自己手动添加,并且还要告诉公司的其他开发人员,你们在添加接口时也需要自己手动的添加,如果忘记的话那么在线上查寻时就找不到该接口的监控日志信息等。

怎么办呢?Express的中间件此时就体现出重要的优势了,我们可以自己写一个中间件,然后每次不同接口请求的时候都要执行这个中间件然后携带上我们需要添加的信息,那么这个时候开发人员就不需要关注我是否每一次添加新的接口时需要处理相关的信息,而专心开发相关的业务逻辑即可。

下面用代码举个例子:

(1)没有使用中间件时的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 没有使用中间件时,每一个接口都需要自己单独处理
const express = require('express');
const app = express();
app.get('/aaa', (req, res, next) => {
console.log('没有使用中间件需要自己单独处理aaa'); // 需要自己处理
res.send('我是aaa接口处理信息');
});
app.get('/bbb', (req, res, next) => {
console.log('没有使用中间件需要自己单独处理bbb'); // 需要自己处理
res.send('我是bbb接口处理信息');
});
app.listen(8888, () => {
console.log('端口8888 success');
});

(2)使用了中间件时的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 使用中间件后,中间件会帮我们处理而我们就不需要处理了
const express = require('express');
const app = express();
// 中间件,在这里第一个参数pathname不写,任何请求都会执行这个中间件
app.use((req, res, next) => {
console.log('使用中间件,中间件帮忙处理');
next();
});
app.get('/aaa', (req, res, next) => {
res.send('我是aaa接口处理信息');
});
app.get('/bbb', (req, res, next) => {
res.send('我是bbb接口处理信息');
});
app.listen(8888, () => {
console.log('端口8888 success');
});

2. 中间件原理以及如何实现

中间件的原理:需要利用闭包,然后每调用一次use,就把use中传入的函数push到Express内部维护的数组中,当我们调用next的时候其实就去Express内部维护的数组中去取相关的函数执行。简单理解思路之后我们再来看看代码是如何实现的:

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
const http = require('http');
function express () {
let funcs = []; // 存储待执行函数数组
let app = function (req, res) {
let i = 0;
const next = function () {
const task = funcs[i++];
if (!task) {
return;
}
task(req, res, next);
};
next();
};
// use方法其实就是把中间件函数添加到存储待执行函数数组中
app.use = function (task) {
funcs.push(task);
};
return app;
}
const app = express();
app.use((req, res, next) => {
console.log('中间件1');
next();
});
app.use((req, res, next) => {
console.log('中间件2');
next();
});
http.createServer(app).listen(8888, () => {
console.log('8888 port is running....');
});

使用Postman工具去随便请求一个接口时,在终端就会打印出中间件1、中间件2。在这里我们就实现了Express中间件,如果你感觉还有点迷糊的话,那么就先弄明白中间件的使用,然后在仔细分析一下上面的代码,然后自己多敲几遍就明白了。当然在上面我们还看到了node提供的核心模块http,带我看完http中createServer的源码之后再来给你讲解它是如何封装的。
客官请留步,如果你觉得这篇文字对你有帮助的话,不妨来个三连再走。