中间件
中间件:特指业务流程中的中间处理环节 Express的中间件,实质上就是一个function处理函数,格式如下:
//这里的function 就是中间件函数
app.get('/',function(req,res,next){
next();
})
注意,中间件函数的形参列表中,必须包含next参数,而路由处理函数中只包含req和res. next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
全局生效的中间件
客户端发起的请求,达到服务器之后,都会触发的中间件,叫做全局生效的中间件,通过调用app.use(中间件函数),即可定义一个全局生效的中间件。
const express = require('express')
const app = express()
//next()表示把流转关系转交给下一个中间件或路由,由于没有下一个中间件,因此交给了/或/user路由
const mw = function(req,res,next){
console.log('调用了mw中间件');
next();
}
app.use(mw)
app.get('/',(req,res)=>{
console.log('经过/路由');
res.send('/')
})
app.get('/user',(req,res)=>{
console.log('经过/user路由');
res.send('/user')
})
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
中间件的作用:多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义属性或方法,供下游的中间件或路由使用。
const express = require('express')
const app = express()
const mw = function(req,res,next){
//在中间件中获取到达服务器的时间
const time = Date.now()
//挂载在req的自定义属性startTime上
req.startTime = time;
next();
}
app.use(mw)
app.get('/',(req,res)=>{
//下游路由可以获取到req的自定义属性
res.send('Home page' + req.startTime)
})
app.get('/user',(req,res)=>{
res.send('user page' + req.startTime)
})
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
可以使用app.use()连续定义多个全局中间件,客户端到达服务器之后,会根据中间件定义的先后顺序依次进行调用。
局部生效的中间件
不适用app.use()定义的中间件,叫做局部中间件,直接把中间件名称加载路径之后即可:
const express = require('express')
const app = express()
const mw = function(req,res,next){
console.log('调用了中间件');
next();
}
//调用了局部中间件
app.get('/',mw,(req,res)=>{
res.send('Home page')
})
//没有调用局部中间件
app.get('/user',(req,res)=>{
res.send('user page')
})
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
可以通过如下两种方式,使用多个局部中间件:
app.get('/user',mw1,mw2,(req,res)=>{res.send('user page')})
app.get('/user',[mw1,mw2],(req,res)=>{res.send('user page')})
注意:一定要在路由之前注册中间件!!!
中间件的分类
- 应用级别的中间件:通过app.use()或app.get()或app.post(),绑定到app实例上的中间件,叫做应用级别中间件
- 路由级别的中间件:绑定到express.Router()实例上的中间件
- 错误级别的中间件:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。错误级别的中间件function函数中,必须包括4个形参(err,req,res,next)。错误级别的中间件必须放在所有的路由之后!!!
const express = require('express')
const app = express()
app.get('/',(req,res)=>{
throw new Error('服务器内部出错');
res.send('Home page')
})
app.use((err,req,res,next)=>{
console.log('发生了错误:'+err.message);
res.send('Error!'+err.message);
})
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
- Express内置中间件:express.static快速托管静态资源的内置中间件;express.json解析JSON格式的请求体数据;express.urlencoded解析URL-encoded格式的请求体数据;
app.use(express.json())
app.use(express.urlencoded({extended:false}))
app.post('/user',(req,res)=>{
//在服务器,可以使用req.body这个属性,来接受客户端发送过来的请求体数据
//默认情况下,如果不配置解析表单数据的中间件,则req.body默认等于undefined
console.log(req.body);
res.send('ok')
})
app.post('/book',(req,res)=>{
console.log(req.body);
res.send('ok')
})
- 第三方的中间件:按需下载导入并app.use()配置第三方中间件
自定义中间件
自己手动模拟一个类似express.urlencoded这样的中间件,来解析POST提交到服务器的数据
//custom-body-patser.js
const qs = require('querystring')
const bodyParser = (req,res,next)=>{
//str用来存储客户端发送过来的数据
let str = ''
//监听req的data事件(客户端发送过来的请求体数据)
req.on('data',(chunk)=>{
str += chunk
})
//监听req的end事件
req.on('end',()=>{
//str是完整请求体数据
// querystring模块,是用来专门处理查询字符串,通过这个模块的parse()函数,可以轻松解析对象的格式
const body = qs.parse(str)
//解析出来的对象挂载到req.body上
req.body = body
next()
})
}
module.exports = bodyParser
const express = require('express')
const app = express()
const customBodyParser = require('./custom-body-parser.js')
app.use(customBodyParser)
app.post('/user',(req,res)=>{
res.send(req.body)
})
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
|