Express 中间件
中间件(Middleware ),特指业务流程的中间处理环节
1.调用流程
当一个请求到达 Express 的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bqc2e537-1650441667591)(C:\Users\1301338853\AppData\Roaming\Typora\typora-user-images\image-20220420094522143.png)]
上一个中间件的输出会作为下一个中间件的输入
2.格式
中间件的本质上就是一个function 处理函数,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IPDRJ9xe-1650441667592)(C:\Users\1301338853\AppData\Roaming\Typora\typora-user-images\image-20220420101242110.png)]
注意:中间件函数的形参列表中,必须包含 next 参数。而路由处理函数中只包含 req 和 res。
next 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由
3.定义中间件函数
// mw 所指向的就是一个中间件函数
const mw=function(req,res,next){
console.log("这是一个简单的中间件")
next();
}
→全局生效的中间件
客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件
通过调用 app.use(中间件函数),即可定义一个全局生效的中间件
......
const mw=function(req,res,next){
console.log("这是一个简单的中间件")
next(); // 把流转关系,转交给下一个中间件或
}
// 全局生效的中间件
app.use(mw);
app.get("/",(req,res)=>{
console.log("调用了 / 这个路由")
res.send("Home Page")
})
app.get("/user",(req,res)=>{
console.log("调用了 /user 这个路由")
res.send("User Page")
})
......
全局中间件的简化形式
app.use(function(req,res,next){
console.log("这是一个简单的中间件")
next(); // 把流转关系,转交给下一个中间件或
})
中间件的作用
多个中间件之间,共享同一份 req 和 res。基于这样的特性,我们可以在上游的中间件中,统一为 req 或 res 对象添加自定义的属性或方法,供下游的中间件或路由进行使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WvTKtZVf-1650441667593)(C:\Users\1301338853\AppData\Roaming\Typora\typora-user-images\image-20220420113828991.png)]
......
app.use((req, res, next) => {
// 获取到请求到达服务器的时间
const time = Date.now()
// 为 req 对象,挂载自定义属性,从而把时间共享给后面的所有路由
req.startTime = time
next()
})
app.get('/', (req, res) => {
res.send('Home page.' + req.startTime)
})
app.get('/user', (req, res) => {
res.send('User page.' + req.startTime)
})
......
定义多个全局中间件
可以使用 app.use() 连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用
→局部生效的中间件
不使用 app.use() 定义的中间件,叫做局部生效的中间件
.....
const mw1 = (req, res, next) => {
console.log('调用了局部生效的中间件')
next()
}
// mw1 这个中间件只在当前路由中生效
app.get('/', mw1, (req, res) => {
res.send('Home page.')
})
app.get('/user', (req, res) => {
res.send('User page.')
})
.....
多个局部中间件
app.get("/",mw1,mw2,(req,res)=> { } )
4.注意事项
- 一定要在路由之前注册中间件
- 客户端发送过来的请求,可以连续调用多个中间件进行处理
- 执行完中间件的业务代码之后,不要忘记调用 next() 函数
- 为了防止代码逻辑混乱,调用 next() 函数后不要再写额外的代码
- 连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象
→中间件的分类
-
应用级别的中间件
定义:通过全局中间件或 局部中间件,绑定到 express() 实例上的中间件
const express=require("express"); const app=express(); // app 为 express() 实例 // 全局中间件 app.use( (res,req,next)=>{ ....; next() } ) // 局部中间件 app.get[post]("/",中间件,()=> { } )
-
路由级别的中间件
定义:绑定到 express.Router() 实例上的中间件,叫做路由级别的中间件
const express=require("express"); const router=express.Router(); router.use((res,req,next)=>{....; next() } ) app.use("/",router);
-
错误级别的中间件
作用:专门用来捕获整个项目中发生的异常错误,防止项目异常崩溃
// 格式:必须有 4 个形参,形参顺序从前到后,分别是 (err, req, res, next) // 1. 定义路由 app.get('/', (req, res) => { // 1.1 人为的制造错误 throw new Error('服务器内部发生了错误!') res.send('Home page.') }) // 2. 定义错误级别的中间件,捕获整个项目的异常错误,从而防止程序的崩溃 app.use((err, req, res, next) => { console.log('发生了错误!' + err.message) res.send('Error:' + err.message) })
错误级别的中间件,必须注册在所有路由之后!
-
Express 内置的中间件
自 Express 4.16.0 版本开始,Express 内置了 3 个常用的中间件
-
express.static 快速托管静态资源的内置中间件(html css 图片等)
-
express.json 解析 JSON 格式的请求体数据 (表单)
-
express.urlencoded 解析 URL-encoded 格式的请求体数据 (表单)
// 通过 express.json() 这个中间件,解析表单中的 JSON 格式的数据 app.use(express.json()) // 配置解析:application/x-www.form-urlencoded 格式数据的内置中间件 app.use(express.urlencoded({ extended: false })) app.post('/user', (req, res) => { console.log(req.body) res.send('ok') }) app.post('/book', (req, res) => { // 在服务器端,可以通过 req,body 来获取 JSON 格式的表单数据和 url-encoded 格式的数据 console.log(req.body) res.send('ok') })
- 在服务器,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据
- 默认情况下,如果不配置解析表单数据的中间件,则 req.body 默认等于 undefined
-
-
第三方的中间件
Express 内置的 express.urlencoded 中间件,就是基于 body-parser 这个第三方中间件进一步封装出来的
-
自定义中间件
})
```
- 在服务器,可以使用 **req.body** 这个属性,来接收客户端发送过来的请求体数据
- 默认情况下,如果不配置解析表单数据的中间件,则 *req.body 默认等于 undefined*
-
第三方的中间件
Express 内置的 express.urlencoded 中间件,就是基于 body-parser 这个第三方中间件进一步封装出来的
-
自定义中间件