中间件(Middleware),特指业务流程的中间处理环节
1、调用流程
当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
2、格式
Express的中间件,本质上就是一个function处理函数
,Express中间件的格式如下:
app.get('/',(req,res,next) => {
next()
})
中间件的形参列表中,必须包含next
参数,而路由处理函数只包含 req 和 res
3、next函数的作用
next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由
4、定义中间件函数
const vm = function(req,res,next) {
console.log('这是最简单的中间件函数');
// 把流转关系转交给下一个中间件或路由
next()
}
5、全局生效的中间件
客户端发起的任何请求,到达服务器之后,都会触发的中间件
通过app.use(中间件函数),即可定义一个全局生效的中间件
const vm = function(req,res,next) {
console.log('这是最简单的中间件函数');
// 把流转关系转交给下一个中间件或路由
next()
}
app.use(vm)
6、中间件的作用
多个中间件之间共享一份req
和 res
。可以在上游的中间件中,统一为 req 或 res 对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
7、定义多个全局中间件
可以使用app.use()
连续定义多个全局中间件。客户请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用
app.use(function(req,res,next) {
console.log('调用了第一个中间件');
next()
})
app.use(function(req,res,next) {
console.log('调用了第二个中间件');
next()
})
app.get('/',(req,res) => {
res.send('OK.')
})
当请求http://127.0.0.1/
时
8、局部生效的中间件
不使用 app.use()
定义的中间件为局部生效的中间件
const vm = function(req,res,next) {
console.log('调用了局部生效的中间件');
next()
}
app.get('/',vm,(req,res) => {
res.send('Home Page.')
})
app.get('/user',vm,(req,res) => {
res.send('User Page.')
})
vm中间件只会在/
路由中生效,不会影响其他的路由。当请求http://127.0.0.1/
时控制台有打印,请求http://127.0.0.1/user
时,控制台没有打印。
9、定义多个局部中间件
app.get('/',mw1,mw2,(req,res) => {})
app.get('/',[mw1,mw2],(req,res) => {})
如上两种写法是等价的
10、了解中间件的注意事项
① 一定要在路由之前注册中间件
② 客户端发过来的请求,可以连续调用多个中间件进行处理
③ 执行完中间件的业务代码之后,要调用 next() 函数
④ 为了防止代码逻辑混乱,调用 next() 函数后不要再写额外的代码
⑤ 连续调用多个中间件时,多个中间件之间共享 req 和 res 对象
11、中间件的分类
1、应用级别的中间件
通过 app.use() 或 app.get() 或 app.post(),绑定到 app
实例上的中间件
2、路由级别的中间件
绑定到 express.Router()
路由实例上的中间件
var app = express()
var router = express.Router()
router.use(function(req,res,next) {})
3、错误级别的中间件
专门用来捕获整个项目中发生的异常信息,从而防止项目异常崩溃的问题
格式:function处理函数中,必须有4个形参,从前到后分别是(err
、req、res、next)
app.get('/',(req,res) => {
throw new Error('服务器内部发生了错误!')
res.send('Home Page.')
})
此时通过http://127.0.0.1/
访问服务器,服务器就发生了崩溃
// 定义错误级别的中间件捕获整个项目的异常错误,从而防止程序的崩溃
app.use((err,req,res,next) => {
res.send('Error:' + err.message)
})
此时通过http://127.0.0.1/
访问服务器,服务器虽然发生了错误,但是没有崩溃
注意:错误级别的中间件必须注册在所有路由之后
4、Express内置的中间件
自 Express 4.16.0 版本开始,Express内置了3个常用的中间件,极大的提高了Express项目的开发效率和体验
① express.static
快速托管静态资源的内置中间件,例如:HTML文件、图片、CSS样式等(无兼容性)
② express.json
解析 JSON 格式的请求体数据(有兼容性,仅在 4.16.0+版本中可用)
app.post('/user',(req,res) => {
// 通过 req.body 来接收客户端发送过来的请求体数据
console.log(req.body)
res.send('ok')
})
访问 http://127.0.0.1/user
,并使用post请求发送JSON
格式的参数,如 {"name":"zs","age":18}
如上打印 req.body
值为 undefined
app.use(express.json())
app.post('/user',(req,res) => {
console.log(req.body)
res.send('ok')
})
配置了解析JSON格式的请求体数据的中间件,打印 req.body
值为 {name:'zs',age:'18'}
③ express.urlencoded
解析 URL-encoded 格式的请求体数据(有兼容性,仅在 4.16.0+版本中可用)
app.post('/user',(req,res) => {
console.log(req.body)
res.send('ok')
})
访问 http://127.0.0.1/user
,并使用post请求发送x-www-form-urlencoded
格式的参数,如 key:name,value:zs
、key:age,value:18
,如上打印 req.body
值为 undefined
app.use(express.json())
app.post('/user',(req,res) => {
console.log(req.body)
res.send('ok')
})
配置的是解析JSON格式的请求体数据的中间件,打印 req.body
值为 {}
app.use(express.urlencoded({extended:false}))
app.post('/user',(req,res) => {
console.log(req.body)
res.send('ok')
})
配置了解析表单中 urlencoded 格式的请求体数据的中间件,打印 req.body
值为 {name:'zs',age:'18'}
5、第三方中间件
非 Express 官方内置的,而是由第三方开发出来的中间件为第三方中间件。可以按需下载并配置,从而提高项目的开发效率
如 body-parser
这个第三方中间件用来解析请求体数据
① 运行 npm i body-parser
② 使用 require
导入中间件
③ 调用app.use()
注册并使用中间件
const parser = require('body-parser')
app.use(parser.urlencoded({extended:false}))
注意:Express内置的express.urlencoded
中间件,就是基于body-parser
这个第三方中间件进一步封装出来的
6、自定义中间件
手动模拟一个类似于 express.urlencoded 的中间件,来解析POST提交到服务器的表单数据
① 定义中间件
② 监听 req 的 data 事件
③ 监听 req 的 end 事件
④ 使用 querystring 模块解析请求体数据
⑤ 将解析出来的数据对象挂载为 req.body
⑥ 将自定义中间件封装为模块
1、定义中间件
app.use((req,res,next) => {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->})
2、监听 req 的 data 事件
监听 req 对象的 data 事件来获取客户端发送到服务器的数据。
如果数据量比较大无法一次性发送完毕,则客户端会把数据切割后分批发送到服务器,每次触发 data 事件获取到的数据只是完整数据的一部分,需要手动对接收的数据进行拼接
app.use((req,res,next) => {
// 1. 定义一个变量,专门用来存储客户端发送过来的请求体数据
let str = ''
// 2. 监听req的data事件
req.on('data',(chunk) => {
str += chunk
})
})
3、监听 req 的 end 事件
当请求体数据接收完毕之后,会自动触发 req 的 end 事件
app.use((req,res,next) => {
let str = ''
req.on('data',(chunk) => {
str += chunk
})
// 3.监听req的end事件
req.on('end',() => {
// 在str中存放的是完整的请求体数据
console.log(str);
})
})
得到的值为:name=zs&age=18&gender=%E7%94%B7
4、使用 querystring 模块解析请求体数据
Node.js 内置了一个 querystring
模块,专门用来处理查询字符串。通过这个模块提供的 parse()
函数,可以把查询字符串解析成对象的格式
const qs = require('querystring')
app.use((req,res,next) => {
let str = ''
req.on('data',(chunk) => {
str += chunk
})
req.on('end',() => {
// 4.把字符串格式的请求体数据解析成对象格式
const body = qs.parse(str)
console.log(body)
})
})
得到的值为:{ name: 'zs', age: '18', gender: '男' }
5、将解析出来的数据对象挂载为 req.body
上游的中间件和下游的中间件及路由之间共享同一份 req
和 res
。因此可以将解析出来的数据挂载为 req 的自定义属性,命名为 req.body 供下游使用
const qs = require('querystring')
app.use((req,res,next) => {
let str = ''
req.on('data',(chunk) => {
str += chunk
})
req.on('end',() => {
const body = qs.parse(str)
// 5. 将解析出来的请求体对象挂载为 req.body 属性,最后要调用 next() 函数执行后续的业务逻辑
req.body = body
next()
})
})
6、将自定义中间件封装为模块
把自定义的中间件函数封装为独立的模块 custom-body-parser.js
const qs = require('querystring')
const bodyParser = function(req,res,next) {
let str = ''
req.on('data',(chunk) => {
str += chunk
})
req.on('end',() => {
const body = qs.parse(str)
req.body = body
next()
})
}
module.exports = bodyParser
使用:
// 导入自己封装的中间件模块
const customBodyParser = require('./custom-body-parser')
// 将自定义的中间件函数注册为全局可用的中间件
app.use(customBodyParser)
到此这篇关于NodeJs Express中间件使用流程解析的文章就介绍到这了,更多相关NodeJs Express中间件内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!