目录
一.了解中间件
中间件(Middleware)是一个概念
用来特指业务流程的中间处理环节
在我们的Express服务器中,也是这样的道理,当客户端请求到达Express服务器后,调用多个中间件来对这次请求进行预处理,处理完毕之后,才会将处理完成的结果给到路由来完成响应
二.定义中间件
1.定义一个局部生效的中间件
Express的中间件本质其实就是一个function处理函数
语法:服务器实例.get('/',(req,res,next) => {
next()
})
我们发现好像和路由没有什么区别呀,只是多了一个next这个形参,而路由只有req和res俩个形参
我们在上图也看到了每一个的中间件后面都有一个next()函数,那我们就不难理解了,next()函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件,或者转交给路由
next()是必须要写的,并且要写在中间件处理程序的最后
接下来我们定义一个中间件:
const express = require('express')
const app = express()
const mw = (req,res,next) => {
console.log("中间件说你好")
next()
}
app.get('/',mw,(req,res) => {
console.log("路由说你好")
})
app.listen(80,() => {
console.log("server at http://127.0.0.1")
})
我们发现请求会先由中间件处理,处理完毕交给路由处理,由路由来响应这次请求
上面的中间件赋值给了mw,所以对应的get请求需要携带一个mw的参数,这只是单一的对应,接下来我们来定义一个全局生效的中间件
2.定义一个全局生效的中间件
那什么全局中间件呢?
当客户端发起请求,到达服务器后,无论是什么样的无论是哪个请求,都会触发这个中间件,就是全局中间件,我们在之前说过全局中间件的定义方法:
服务器实例.use(mw)
这样我们就可以定义一个全局的中间件了:
const express = require('express')
const app = express()
const mw = (req,res,next) => {
console.log("你好")
next()
}
app.use(mw)
app.get('/',(req,res) => {
res.send('你好')
})
app.listen(80,() => {
console.log("server at http://127.0.0.1")
})
当使用了use方法,这个中间件就会变为全局生效中间件了
tips:当我们定义了多个中间件并use后,客户端请求到达服务器会按照定义的先后顺序来依次进行调用
3.定义多个中间件遇到的问题
那会不会有这么一种情况:我们定义了多个中间件,可是我们不想把这多个中间件转换为全局中间件,我们只想让一个路由来挂载,那么我们该怎么书写呢?
我们可以:
app.post('/api',[mw,mw2,mw3],(req,res) => {
})
或者是:
app.post('/api',mw,mw2,mw3,(req,res) => {
})
4.中间件有什么作用?
中间件有什么特殊的功能?
在多个中间件之间,可以共享一份req和res数据,那么这样的一想,我们是否可以在上游中间件中统一为req或者res对象添加自定义属性或者方法,让下游的中间件以及路由来使用
const express = require('express')
const app = express()
const mw = (req,res,next) => {
//声明time变量存储发起请求的那刻时间
const time = Date.now()
//给到req的自定义属性startTime,供下游使用
req.startTime = time
console.log("你好")
next()
}
app.use(mw)
app.get('/',(req,res) => {
console.log("你好")
//下游输出
res.send('你好'+req.startTime)
})
app.listen(80,() => {
console.log("server at http://127.0.0.1")
})
5.总结
我们来总结一下中间件的使用注意事项:
1.一定要在路由前注册中间件
2.next()函数不要忘
3.next()函数之后不要再去书写代码
4.连续调用多个中间件时,共享req.res
三.中间件的分类
1.应用级别中间件
2.路由级别中间件
3.错误级别中间件
4.Express内置中间件
5.第三方中间件
1.应用级别中间件
我们并不陌生,之前我们通过use()、get()、post()绑定到服务器实例上的中间件就是应用级别的中间件
当然,应用级别中间件又可分为全局中间件和局部中间件
2.路由级别中间件
绑定到express.Router()路由实例上的中间件,称为路由级别中间件,我们在之前也阐述过
3.错误级别中间件
这个中间件可以说是非常的有用,是我们必须要掌握的,它专门来捕获整个项目中发生的异常错误,从而防止项目崩溃
语法:服务器实例.get('/',(err,req,res,next) => {
res.send("发生了异常错误 + err.message")
})
我们发现它多出来了一个err形参,err代表错误,也就是检测到错误执行该中间件来避免崩溃,同时,检测到错误将会抛出一个自定义的错误提示
我们来看一下实际应用:
const express = require('express')
const app = express()
app.get('/',(req,res) => {
//这里接收到请求后,我们自定义了一个错误,来看看项目会不会正常运行
throw new Error("出错了")
})
app.listen(80,() => {
console.log("server at http://127.0.0.1");
})
我们没有得到简洁干净明了的错误提示,只是为我们输出了一个html初始化框架,接下来我们使用错误级别的中间件来处理这个问题:
const express = require('express')
const app = express()
app.get('/',(req,res) => {
//这里接收到请求后,我们自定义了一个错误,来看看项目会不会正常运行
throw new Error("出错了")
})
app.use((err,req,res,next)=>{
res.send("请检查" + err.message)
})
app.listen(80,() => {
console.log("server at http://127.0.0.1");
})
可见错误级别中间件很重要,没有它,我们的项目只要出现了错误就会崩溃掉
tips:错误级别的中间件是也是唯一一个需要写在路由之后的中间件
4.Express内置中间件
我们有三个常用的Express内置中间件:
express.static():快速的托管静态资源的内置中间件
app.use(express.static())
express.json():解析JSON格式的请求体数据的中间件
app.use(express.json())
express.urlencodeed:解析URL-encoded格式的请求体数据
app.use(express.urlencoded({extends:false}))
express.static()我们之前阐述过,这里主要阐述一下json格式转换和url-encoded格式的转换:
express.json(): 假如客户端发起了一个post请求,将一个json格式的数据发送到了我们的服务器,我们可以不使用json解析中间件可以获得到数据吗?
const express = require('express') const app = express() app.post('/',(req,res) => { //使用req.body来接收客户端发来的请求体数据 console.log(req.body); res.send("ok") }) app.listen(80,() => { console.log("server at http://127.0.0.1"); })
我们使用postman来模拟客户端发起的post请求,将一段json格式的数据发送到服务器:
没有错误,一切都正常进行,当我们打开终端查看客户端发来的数据时:
为什么是undefined?因为我们不能解析json数据,需要转换,当我们使用express.json():
const express = require('express') const app = express() app.use(express.json()) app.post('/',(req,res) => { console.log(req.body); res.send("ok") }) app.listen(80,() => { console.log("server at http://127.0.0.1"); })
这次我们在终端中打印出了用户提交的json数据,可以说这是必不可少的中间件,非常的重要
express.urlencoded():假如客户端这次发送了一个URL-encoded格式的数据呢?
成功,接下来我们打开终端:
又是一个undefined,接下来我们使用express.urlencoded()中间件:
const express = require('express') const app = express() app.use(express.json()) app.use(express.urlencoded({extends:false})) app.post('/',(req,res) => { console.log(req.body); res.send("ok") }) app.listen(80,() => { console.log("server at http://127.0.0.1"); })
成功,但是我们好像发现了一点新东西,在服务器启动前body-parser是什么?
其实,这就是我们接下来要阐述的第三方中间件
5.第三方中间件
顾名思义,并不是express内置的,而是第三方提供的中间件
刚才我看到的body-parser就是一个第三方中间件,是用来解析urlencoded数据格式的第三方中间件,那我们在使用内置中间件时为什么会出现它?
其实是因为express内置的express.urlencoded({extends:false})中间件就是基于第三方body-parser这个第三方中间件进一步封装的
我们可以下载这个第三方中间件来使用它,效果和内置中间件一样,我们不做演示:
#下载(终端进行)
npm i body-parser
#导入(JS)
require('body-parser')
#调用(JS)
服务器实例.use()