在其他的开发语言比如C#的ASP.net中,中间件是指业务处理中使用到的组件或者模型。
在Node.js的Express中,就是指在业务处理流程中系统使用到的“组件”,不过,这个“组件”指的是函数而已。
当我们使用Express开发了一个网站,服务器接收到一个来自客户端浏览器的请求之后,最简单的情形就是经过一个函数处理后就返回结果,而普遍存在的场景却是需要连续调用多个处理函数(中间件,middleware)后才能给客户端返回结果。
比如,做提取来自客户端的基础信息(IP地址、访问时间、请求的源地址等)、安全检测、记录日志、通讯处理及消息传递等等,这些处理需求对于一个稍微大一点的网站几乎是必须的,这些就可以写成中间件,我们在开发过程中就可以很方便地使用它们从而对来自浏览器端的请求逐一做想要的预处理。
在Node.js的Express中,多个中间件之间,共享同一份的req(request)和res(response),并且在前面使用的中间件中,可以为req和res添加自定义的属性或者方法,以便让后面的中间件进行使用。
1、Express中间件的格式:(app为Web服务器的实例对象)
app.post(‘路由请求’,(req,res,next)=>{
//处理
//移交给下一个中间件或者路由
next()
})
2、在Express中,中间件分局部生效的中间件和全局生效的中间件。
① 局部生效的中间件
const ztb_mw1=function(req,res,next){
console.log(‘局部生效的中间件1’)
next()
}
const ztb_mw2=function(req,res,next){
console.log(‘局部生效的中间件2’)
next()
}
app.post(‘/ZTB’,ztb_mw1,ztb_mw2,function(req,res){
res.send(‘这是经过两个中间件处理后的结果’)
}
上面的等价形式:
app.post(‘/ZTB’,[ztb_mw1,ztb_mw2],(req,res)=>{
res.send(‘这是经过两个局部生效的中间件处理后的结果’)
}
② 全局生效的中间件
app.use(function(req,res,next){
console.log(‘这是全局生效的中间件1’)
next()
})
app.use(function(req,res,next){
console.log(‘这是全局生效的中间件2’)
next()
})
app.post(‘/ZTB’,(req,res)=>{
res.send(‘这是经过两个全局中间件处理后的结果’)
}
3、中间件分为5大类:
① 处理一般应用的中间件:
通过app.post()、app.get()或者app.use()绑定到app实例上的中间件。
② 处理路由的中间件:
绑定在router实例上的中间件,router为路由实例对象
③ 处理错误的中间件
处理错误的中间件,有4个参数,分别是err,req,res,next,这个中间件必须注册在所有的路由之后。
④ Express的内置中间件
比如express.json、express.urlencoded等,其中express.json用于解析JSON格式的请求体数据(在Express 4.16版本之后),express.urlencoded用于解析URL-encoded格式的请求体数据。
⑤ 第三方的中间件
这个有很多,使用类同于express的内置组件。
4、定义中间的注意事项:
① 一定要在路由之前注册中间件;
② 对于同样的请求,可以连续调用多个中间件
③ 执行完中间件,最后一定要调用next()函数
④ 连续调用的多个中间件之间共享同一份的req和res对象
主文件ZTB_Main.js代码:
//导入express模块
const express=require('express')
//创建Web服务器
const app=express()
//配置解析application/json格式的数据的中间件
app.use(express.json())
//配置解析application/x-www-form-urlencoded格式数据的中间件
app.use(express.urlencoded({extended:false}))
//导入自定义的路由模块
//自定义模块必须加上路径名,文件后缀可以省略,内置模块和下载的第三方模块不需要加
const ZTB_router=require('./ZTB_router.js')
//导入中间件模块
const ZTB_mw=require('./ZTB_mw.js')
//注册中间件
app.use(ZTB_mw.ZTB_mw1)
app.use(ZTB_mw.ZTB_mw2)
//注册一个局部路由模块
app.use('/ZTB/update',ZTB_mw.ZTB_mw3,ZTB_router)
//注册全局路由模块
app.use('/ZTB',ZTB_router)
//启动web服务器
app.listen(9019,()=>{
console.log('Web服务器正在运行......http://127.0.0.1:9019')
})
中间件文件ZTB_mw.js代码:
//导入express
var express=require('express')
function ZTB_mw1(req,res,next){
console.log('获取客户端的信息')
next()
}
function ZTB_mw2(req,res,next){
console.log('安全检测')
next()
}
function ZTB_mw3(req,res,next){
console.log('日志处理')
next()
}
//对外共享中间件
module.exports={
ZTB_mw1,
ZTB_mw2,
ZTB_mw3
}
路由文件ZTB_router.js代码:
//导入express
var express=require('express')
//创建路由对象
var router=express.Router()
router.get('/add',function(req,res){
//处理增加
//返回结果
console.log('增加操作')
res.send('增加操作')
})
router.post('/del',function(req,res){
//处理删除
//返回结果
console.log('删除操作')
res.send('删除操作')
})
router.post('/update',function(req,res){
//处理删除
//返回结果
console.log('更新操作')
res.send('更新操作')
})
//对外导出路由对象
module.exports=router
结果: