中间件是什么呢?

中间件就是客户端http请求发起传送到服务器和服务器返回响应之间的一些处理函数。

 

为什么要使用中间件?

通过中间件,可以对数据进行操作使得我们能方便地操作请求数据编写服务器响应。如body-parse中间件对post请求的参数进行处理让我们可以通过res.body快速获取请求参数,express-session中间件可以让我们对数据进行保存,express.static是express内置中间件,可以让我们快速处理静态资源,express.Router路由中间件等等
 
中间件如何使用?
Express中,对中间件进行了几种分类:
1.不关心请求路径和请求方法的中间件,通过app.use函数实现
app.use(function(req,res,next){})
客户端发起的任意请求都会经过这个中间件函数进行处理
next指下一个满足路径条件的中间件,如果有执行next,那么这个中间件执行完后就会执行下一个满足条件的中间件,如果没有next,就会忽略后面所有中间件
 
以下面代码为例(设服务器ip为127.0.0.1,后面所有例子都以该ip为例)
var express = require('express')
var app = express()

app.use(function(req,res) {
    res.end('404 NOT FOUND')
}

app.listen(3000,function(){
    console.log('running...');
}

所有对该服务器的请求最终都会返回404 NOT FOUND,无论是路径是什么

2.关心请求路径的中间件,通过app.use函数实现
app.use(路径,function(req,res,next){})
客户端发起的以第一个参数开头的路径才会进入该中间件
 
以下代码为例
var express  = require('express')
var app = express()

app.use('/public',function(req,res,next) {
    res.end('you are public');
}

app.listen(3000,function(){
    console.log('running...')
}

 只要客户端访问该服务器的地址是以public开头(即127.0.0.1:3000/public/xxx),那么就会返回you are public 字符串

 

3.严格匹配路径的中间件,通过app.get/app.post等实现
也就是我们所说的服务器路由
app.get(路径,函数)
app.post(路径,函数)
只有严格匹配请求方式和请求路径的请求才会进入该中间件
 
以下面代码为例
var express = require('express')
var app = express()

// 中间件1 app.get('/get/puclic',function(req,res){ res.end('get!'); } // 中间件2 app.post('/post/public',function(req,res) { res.end('post!'); } app.listen(3000,function(){ console.log('running...'); }

 客户端只有通过get方式访问127.0.0.1:3000/get/public时才会进入中间件1,只有通过post方式访问127.0.0.1:3000/post/public时才会进入中间件2,只有这两者完全匹配才会进入对应的中间件

 

中间件的执行机制:
1.中间件的第一次执行是同步的,当一个请求发出到达服务器后,则按照顺序匹配所有中间件,当找到一个匹配时,则进入该中间件
2.如果该中间件最后没有执行next函数,则该请求在此中间件终止,不再进入后面的中间件;如果有,则会直接进入后面匹配的中间件中(此时不再是按顺序!)
3.重复1-2步
 
如果把客户端发起请求和服务器发出响应比作自来水的进入水库和输出水库,那么中间件就是水库里对水分别进行过滤沉淀消毒的各个小厂房,而中间件的函数的next参数就相当于每个小厂房的门,只有这个门打开了,处理完的请求的数据才能继续向后面的中间件发送,直至响应发出。
 
 

 

以下面的代码为例进一步说明中间件的执行顺序

var express = require('express');

var app = express()

//中间件1 app.use(function(req,res) { console.log('非严格'); })
//中间件2 app.use('/public',function(req,res,next) { console.log('半严格');
    next(); })
//中间件3 app.get('/public',function(req,res) { console.log('严格 get'); })
//中间件4 app.post('/public',function(req,res) { console.log('严格 post'); })

//中间件5
app.get('/public',function(req,res) { console.log('严格 get'); })
app.listen(3000,function() { console.log('running...') })

 此时客户端访问/public,那么首先会进入中间件1,因为有执行next函数,所以直接寻找后面能够匹配的中间件,进入中间件2,中间有执行next函数,所以进入中间件3,但是中间件3没有next函数,所以不再执行,所以输出的语句是‘非严格’ '半严格' '严格 get'

 

如果是下面代码,请求/public后结果又是怎样呢?

var express = require('express');

var app = express()


app.use('/img',function(req,res) {
	console.log('半严格');
})

app.get('/public',function(req,res) {
	console.log('严格 get');
})

app.post('/public',function(req,res) {
	console.log('严格 post');
})

app.listen(3000,function() { console.log('running...') })

 结果是输出'严格 get',请求到达服务器后,从上往下逐渐匹配,匹配到第二个中间件,进入执行,但是该中间件没有执行next函数,所以终止

 

综上所述,我们可以知道,第三方中间件的安装执行是有讲究的

对于一些封装请求数据方便我们操作以及处理静态资源的中间件我们应该放在路由中间件(即有发出服务器响应的中间件)之前编写,否则在编写路由时就无法使用封装好的数据。而对于返回404页面的路由可以放在所有中间件后面,这样无法找到的页面则会自动匹配到最后一个返回404页面
 
中间件的使用是灵活多变的,本文章只是简单概述其概念及其执行机制,更多技巧仍需读者自行体会