Node.js - 关于 express 中间件(自定义中间件)
需求描述
模拟一个类似 express.urlencoded
这样的中间件,来解析 POST 提交到服务器的表单数据
实现步骤
- 定义中间件
- 监听 req 的 data 事件
- 监听 req 的 end 事件
- 使用 querystring 模块解析请求体数据
- 将解析出来的数据对象挂载为 req.body
- 将自定义中间件封装为模块
具体实现
-
定义中间件
const express = require('express') const app = express() // 定义解析表单数据的中间件 app.use((req, res, next) => { // 定义中间件具体的业务逻辑 }) app.listen(80, ()=> { console.log('express 服务器运行在 http://127.0.0.1.80') })
-
监听 req 的 data 事件
在中间件中, 需要监听 req 对象的 data 事件,来获取客户端发送到服务器的数据
如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以 data 事件可能会触发很多次,每一次触发 data 事件时,获取到数据只是完整数据的一部分,需要手动对接收的数据进行拼接
const express = require('express') const app = express() // 定义解析表单数据的中间件 app.use((req, res, next) => { // 定义中间件具体的业务逻辑 //1、定义一个空字符串,用来存放客户端发送来的请求体数据 let str = '' //2、监听 req 的 data 事件 req.on('data', (chunk)=>{ str += chunk }) }) app.listen(80, ()=> { console.log('express 服务器运行在 http://127.0.0.1.80') })
-
监听 req 的 end 事件
当请求体数据接收完毕之后,会自动触发 req 和 end 事件,因此,可以在 req 的 end 事件中,拿到并处理完整的请求体数据
const express = require('express') const app = express() // 定义解析表单数据的中间件 app.use((req, res, next) => { // 定义中间件具体的业务逻辑 //1、定义一个空字符串,用来存放客户端发送来的请求体数据 let str = '' //2、监听 req 的 data 事件 req.on('data', (chunk)=>{ str += chunk }) //3、监听 req 的 end 事件 req.on('end', () => { // 在 str 中存放的时完整的请求体数据 console.log(str) }) }) app.post('/user', (req, res) => { res.send('ok') }) app.listen(80, ()=> { console.log('express 服务器运行在 http://127.0.0.1.80') })
-
使用 querystring 模块解析请求体数据
node.js 内置了一个 querystring 模块,专门用来处理查询字符串,通过这个模块提供的
parse()
函数,可以轻松把查询字符串,解析成对象的格式const express = require('express') //导入处理 querystring 的 node.js 内置模块 const qs = require('querystring') const app = express() // 定义解析表单数据的中间件 app.use((req, res, next) => { // 定义中间件具体的业务逻辑 //1、定义一个空字符串,用来存放客户端发送来的请求体数据 let str = '' //2、监听 req 的 data 事件 req.on('data', (chunk)=>{ str += chunk }) //3、监听 req 的 end 事件 req.on('end', () => { // 在 str 中存放的时完整的请求体数据 console.log(str) //4、把字符串格式的请求体数据,解析成对象格式 const body = qs.parse(str) console.log(body) }) }) app.post('/user', (req, res) => { res.send('ok') }) app.listen(80, ()=> { console.log('express 服务器运行在 http://127.0.0.1.80') })
-
将解析出来的数据对象挂载为
req.body
上游中间件和下游的中间件及路由器之间,共享一份 req 和 res。因此,可以将解析出来的数据,挂载为 req 的自定义属性,命名为 req.body,供下游使用
const express = require('express') //导入处理 querystring 的 node.js 内置模块 const qs = require('querystring') const app = express() // 定义解析表单数据的中间件 app.use((req, res, next) => { // 定义中间件具体的业务逻辑 //1、定义一个空字符串,用来存放客户端发送来的请求体数据 let str = '' //2、监听 req 的 data 事件 req.on('data', (chunk)=>{ str += chunk }) //3、监听 req 的 end 事件 req.on('end', () => { // 在 str 中存放的时完整的请求体数据 console.log(str) //4、把字符串格式的请求体数据,解析成对象格式 const body = qs.parse(str) console.log(body) //5、将解析出来的请求对象,挂载为 req.body req.body = body next() }) }) app.post('/user', (req, res) => { res.send('ok') }) app.listen(80, ()=> { console.log('express 服务器运行在 http://127.0.0.1.80') })
-
将自定义中间件封装为模块
为了优化代码的结构,可以把自定义的中间件函数封装为独立的模块
-
创建一个自定义模块,名为 custom-body-parser,并将之前自定义的中间件函数抽离出来,通过
module.exports
导出//导入处理 querystring 的 node.js 内置模块 const qs = require('querystring') const bodyParser = (req, res, next) => { let str = '' req.on('data', (chunk)=>{ str += chunk }) req.on('end', () => { console.log(str) const body = qs.parse(str) console.log(body) req.body = body next() }) } module.exports = bodyParser
-
外部调用。导入自定义模块,注册为全局可用的中间件
const express = require('express') const app = express() // 1、导入自己封装的中间件模块 const customBodyParse = require('./custom-body-parser') // 2、将自定义的中间件函数,注册为全局可用的中间件 app.use(customBodyParse) app.post('/user', (req, res) => { res.send(req.body) }) app.listen(80, ()=> { console.log('express 服务器运行在 http://127.0.0.1.80') })
-
转载自:https://juejin.cn/post/7084972172183076872