1.中间件介绍
1.1 概念
1.2Express 中间件的调用流程
当一个请求到达Express的服务器之后, 可以连续调用多个中简介。
Express的中间件,本质上就是一个function处理函数,格式如下:
app.get('/user', function(req, res, next){
next()
})
注意中间件函数的形参列表中, 必须包含next参数, 而路由参数中只能包含req和res.
1.3 next() 函数的作用
next函数是实现多个中间件连续调用的关键, 它表示把流转关系转交给下一个中间件或路由。
2. 中间件初体验
注意:
中间件必须放在路由前面, 先执行中间件然后在走路由流程。
在当前中间件的业务流程处理完毕后, 必须调用next()函数, 表示把流转关系转交给下一个中间件或路由。
2.1 全局生效的中间件
客户端发起的任何请求, 到达服务器之后, 都会触发的中间件,叫做全局生效的中间件。
通过调用app.use(中间件函数), 即可定义一个全局生效的中间件,
const express = require('express');
const app = express();
const mw = (req, res, next) => {
console.log('我是第一个中间件')
next()
}
app.use(mw)
app.get('/user', (req, res) => {
res.send('haha')
})
app.listen(80, () => {
console.log('服务正常运行')
})
2.2 中间件的作用
多个中间件之间, 共享一份req和res.基于这样的特性, 我们可以在上游的中间件中统一为req或者res对象添加自定义属性或者方法, 供下游的中间件使用或者路由使用。
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log('我是第一个中间件')
const date = new Date()
req.date = date
next()
})
app.get('/user', (req, res) => {
res.send(req.date)
})
app.get('/info', (req, res) => {
res.send(req.date)
})
app.listen(80, () => {
console.log('服务正常运行')
})
2.3 定义多个全局中间件
可以使用app.use()连续定义多个全局中间件。客户端请求到服务器之后, 会按照中间件定义的先后顺序依次进行调用, 实例代码如下:
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log('我是第一个中间件')
next()
})
app.use((req, res, next) => {
console.log('我是第二个中间件')
next()
})
app.get('/user', (req, res) => {
res.send(req.date)
})
app.get('/info', (req, res) => {
res.send(req.date)
})
app.listen(80, () => {
console.log('服务正常运行')
})
2.4 局部生效的中间件
不使用app.use()定义的中间件,叫做局部生效的中间件, 实例代码如下:
const express = require('express');
const app = express();
const mw1 = (req, res, next) => {
console.log('我是第一个中间件')
next()
}
const mw2 = (req, res, next) => {
console.log('我是第二个中间件')
next()
}
app.get('/user',mw1, (req, res) => {
res.send(req.date)
})
app.get('/info',mw2, (req, res) => {
res.send(req.date)
})
app.listen(80, () => {
console.log('服务正常运行')
})
2.5定义多个中间件
app.get('/user',[mw1, mw2], (req, res) => {
res.send(req.date)
})
app.get('/user', mw1, mw2, (req, res) => {
res.send(req.date)
})
2.6 使用中间件的注意事项
- 一定要在路由之前注册中间件
- 客户端发送过来的请求, 可以来纳许调用多个中间件进行处理
- 执行完中间件的业务代码之后, 不要忘记调用next()函数
- 为了防止代码逻辑混乱, 调用next()函数后不要再写额外的代码
连续调用多个中间件时,多个中间件之间, 共享req和res对象。
3. 中间件的分类
应用级别的中间件
- 路由级别的中间件
- 错误级别的中间件
- Express内置的中间件
- 第三方的中间件
3.1 应用级别的中间件
通过app.use()或app.get()或者app.post(),绑定到实例上的中间件,叫做应用级别的中间件,app.use((req, res, next) => {
console.log('我是第一个中间件')
next()
})
app.get('/user', mw1, mw2, (req, res) => {
res.send(req.date)
})
3.2 路由级别的中间件
绑定到express.Router()实例上的中间件, 叫做路由级别的中间件。 它的用法和应用级别中间件没有任何区别。 只不过, 应用级别中间件是绑定到app实例上的, 路由级别中间件绑定到router实例上。const express = require('express');
const app = express();
const router = express.Router()
router.use( (req, res, next) => {
console.log('路由级别中间件')
req.desc= '我是一个路由级别的中间件'
next()
})
app.use('/user', router)
app.get('/user', (req, res) => {
res.send(req.desc)
})
app.listen(80, () => {
console.log('服务正常运行')
})
3.3错误级别的中间件
错误级别的中间件作用: 专门用来捕获整个项目中发生的一场错误, 从而防止项目一场奔溃的问题。
格式: 错误级别的中间件的function处理函数中, 必须有4个形参, 形参顺序从前至后, 分别是err, req, res, next()。3.4 内置中间件
3.4.1express.static
express.static快速托管静态资源的内置中间件, 例如: HTML文件、图片、CSS样式等(无兼容性) ```javascript const express = require(‘express’); const app = express(); app.use(‘/public’,express.static(‘./src’)) app.get(‘/user’, (req, res) => { res.send(‘哈哈哈’)
}) app.listen(80, () => { console.log(‘server is runnning at 127.0.0.1:80’) })
<a name="QQz51"></a>
### 3.4.2 express.json
解析JSON格式的请求数据(有兼容性)
```javascript
const express = require('express');
const app = express();
//通过express.json这个中间件,间隙表单中的json格式的数据
console.log(app.use(express.json()))
app.post('/add',(req, res) => {
console.log(req.body)
//{ name: 'lisa', age: 20 }
/**
* 在服务器中, 可以使用req.body这个属性 来接收客户端发送过来的请求体数据
* 默认情况下, 如果不配置解析表单数据的中间件,则req.body默认等于undefined
*/
res.send('OK') } ) app.listen(80, () => {
console.log('server is runnning at 127.0.0.1:80')
})
3.4.3 express.urlencoded
- 解析URL-encoded格式的请求体数据(有兼容性)
- 安装中间件:npm install body-parser
- 导入中间件:const parser = require(‘body-parser’)
- 调用中间件:app.use(parser.urlencoded({extended: false}))
注意: Express内置的express.urlencoded中间件, 就是基于body-parser这个第三方中间件进一步封装出来的。const express = require('express');
//导入解析表单数据的中间件 body-parse
const parser = require('body-parser')
const app = express();
//使用app.use注册中间件
app.use(parser.urlencoded({extended: false}))
//通过express.json这个中间件,间隙表单中的json格式的数据
// console.log(app.use(express.urlincoded()))
app.post('/add',(req, res) => {
console.log(req.body)
//{ name: 'Iric', address: '陕西省' }
/**
* 在服务器中, 可以使用req.body这个属性 来接收客户端发送过来的请求体数据
* 默认情况下, 如果不配置解析表单数据的中间件,则req.body默认等于undefined
*/
res.send('OK') } ) app.listen(80, () => {
console.log('server is runnning at 127.0.0.1:80')
})
所以也可以直接使用express.urlencoded解析地址const express = require('express');
const app = express();
app.use(express.urlencoded({extended: false}))
app.post('/add',(req, res) => {
console.log(req.body)
//{ name: 'Iric', address: '陕西省', age: '16' }
/**
* 在服务器中, 可以使用req.body这个属性 来接收客户端发送过来的请求体数据
* 默认情况下, 如果不配置解析表单数据的中间件,则req.body默认等于undefined
*/
res.send('OK') } ) app.listen(80, () => {
console.log('server is runnning at 127.0.0.1:80')
})
3.5 自定义中间件
3.5.1 定义中间件
使用app.use()来定义全局生效的中间件3.5.2 监听req的data事件
:::success 在中间件中, 需要监听req对象的data事件, 来获取客户端到服务器的数据。如果数据量比较大, 无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。 所以data事件可能会触发多次。 每一次触发data事件时, 获取到数据只是完整数据的一部分, 需要手动对接收到的数据进行拼接。 :::3.5.3 监听req的end事件
当请求体数据接收完毕之后, 会自动触发req的end事件。因此,我们可以在req的end事件中, 拿到并处理完整的请求体数据。3.5.4 使用querystring模块解析请求体数据
node.js内置了一个querystring模块, 专门用来处理查询字符串。通过这个模块提供的parse()函数,可以轻松把查询字符串, 解析成对象的格式。3.5.5 将解析出来的数据对象挂载为req.body
上游的中间件和下游的中间件之间,共享一份req和res.因此,我们可以将解析出来的数据, 挂载为req的自定义属性, 命名为req.body,供下游使用。3.5.6 将自定义中间件封装为模块
const express = require('express')
const qs = require('querystring')
const app = express()
//解析表单数据的中间件
app.use((req, res, next) => {
//定义一个str字符串, 专门用来存储客户端发送过来的请求体数据
let str = ''
//监听req对象的data事件(客户端发送过来的新的请求数据)
req.on('data', (chunk) => {
//拼接请求体数据, 隐式转换为字符串
str += chunk;
})
//监听req的end事件
req.on('end', () => {
//把字符串格式的请求体数据, 解析成对象格式
const body = qs.parse(str)
req.body = body;
next()
})
})
app.post('/add', (req, res) => {
res.send(req.body)
})
app.listen(80, () => {
console.log('server is running')
})