Express框架本质上就是由一系列中间件在内部执行。所谓中间件就是一个能访问request/response/next对象的一个函数(这里的next对象其实也是一个中间件),而且每一个中间件都有能力改变request或者response对象,而next就是负责如何让这个请求响应周期向下流转,或者说停止流转的作用,由于中间件是串联执行的,所以中间件在代码中的顺序是非常重要的。假设当前的中间件正在处理您的请求但是不想终止该请求-响应周期,他就必须通过next对象把控制器交给下一个中间件去处理,否则这个请求将会被挂起!通过挂载点(请求的url路径),中间件可以配置在应用级别或者是路由级别,也可以将一连串多个中间件挂在同一个路径下。
1. 应用级别中间件
应用级别的中间件被绑定到express对象上,使用 app.use() 或是 app.VERB()方式挂载。
例1:在一个路径下挂在2个中间件,每个中间件对应一个处理函数,一个匹配所有挂载路径,另一个匹配指定路径1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18var app = express();
// 这个中间件无挂载点,它会处理所有过来的请求
app.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
// 这个中间件挂在在 /user/:id 的路径下; 它会在 /user/:id 请求到来时触发
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next(); //注意这里是next()
});
// 这是个路由请求,2个中间件处理完毕后会交给它处理
app.get('/user/:id', function (req, res, next) {
res.send('USER');
});
例2:在同一个路径下挂在1个中间件的两个函数,它们会按挂载顺序执行1
2
3
4
5
6
7
8// 这个中间件会执行 挂载路径`/user/:id`下的两个函数
app.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next(); //先执行
}, function (req, res, next) {
console.log('Request Type:', req.method);
next(); //后执行
});
路由其实也是一种中间件,因此可以为一个路径定义多条路由,下面的例子里第二个路由没有被执行
例3: 在同一个路径下挂载两个路由函数,注意第一个路由里有个请求-响应结束的处理1
2
3
4
5
6
7
8
9
10
11
12// 处理挂载路径 /user/:id 的路由中间件
app.get('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id);
next();
}, function (req, res, next) {
res.send('User Info'); //这里已经结束了请求-响应周期
});
// 也是处理挂载路径 /user/:id 的路由中间件,没有起到任何作用
app.get('/user/:id', function (req, res, next) {
res.end(req.params.id);
});
刚才例3说到res.send会将请求-响应周期终止,那么如果你想继续执行下一个路由函数,那么在本路由中必须要通过next('route')函数把控制权交给下一个路由,而且注意:next('route')只能在app.VERB() 或者 router.VERB()中使用。
例4:中间件函数内判断路由跳转1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 中间件处理挂载路径 /user/:id
app.get('/user/:id', function (req, res, next) {
// 如果user id == 0 ,则跳转到下一个路由
if (req.params.id == 0) next('route');
// 否在控制权还在当前路由函数,交给当前路由的下一个函数
else next(); //
}, function (req, res, next) {
// 跳转到 regular 视图
res.render('regular');
});
// 中间件处理挂载路径 /user/:id 的指定视图
app.get('/user/:id', function (req, res, next) {
res.render('special');
});
2. 路由级别中间件
路由级别中间件跟应用级别中间件的工作模式是一模一样的,这里就不赘述了,唯一不同的是路由中间件是绑定在express.Router()实例上的,路由级别中间件使用router.use()或者 router.VERB()方式挂载。
例:路由级别中间件的挂载方式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
37var app = express();
var router = express.Router();
// 中间件处理每一个请求
router.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
// 中间件处理挂载路径 /user/:id
router.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
// 路由中间件处理挂载路径 /user/:id
router.get('/user/:id', function (req, res, next) {
// 如果user id == 0 跳转到下一个路由(即路由2)
if (req.params.id == 0) next('route');
// 否则将控制权交给下一个路由函数
else next(); //
}, function (req, res, next) {
// render a regular page
res.render('regular');
});
// 路由2
router.get('/user/:id', function (req, res, next) {
console.log(req.params.id);
res.render('special');
});
// 将路由挂载到 / 路径
app.use('/', router);
3. 第三方中间件
Expressweb框架的特性是通过第三方中间件的添加体现的,假如我们需要mogodb的连接数据库的特性,只要下载mogodb模块,通过npm安装后,然后挂载到express的路由级别或是应用级别就可以了。
下面举例说明如何使用cookie特性,这里先安装cookie-parser模块 $ npm install cookie-parser1
2
3
4
5
6var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');
// 配置 cookie-parser 中间件到应用级别
app.use(cookieParser);
4. 内置中间件
从Express4.x开始只有一个中间件是内置的express.static其它的中间件都不再内置,开发的时候需要我们自己类似第三方中间件的方式扩展特性,可能是为了压缩体积吧,具体我也不太清楚,下面介绍下express.static,其实express.static负责提供系统的静态资源目录,如图片,模板,脚本,样式文件等的目录
**例1: 将public文件目录作为静态资源目录1
2
3
4
5
6
7
8
9
10
11
12
13var options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path) {
res.set('x-timestamp', Date.now())
}
};
app.use(express.static('public', options));
例2: 配置多个目录作为静态资源目录1
2
3app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));
5. 总结
中间件的概念不是很复杂
================================================================post by 午夜圣斗士 QQ | 邮箱 | Github