自定义类似express.urlencoded解析 POST 提交到服务器的表单数据
自定义中间件
1 需求描述与实现步骤
1.1 需求以及实现步骤
-
需求描述: 自己手动模拟一个类似于
express.urlencoded
这样的中间件,来解析 -
实现步骤:
-
定义中间件
-
监听
req
的data
事件 -
监听
req
的end
事件 -
使用
querystring
模块解析请求体数据 -
将解析出来的数据对象挂载为
req.body
-
将自定义中间件封装为模块
-
1.2 定义中间件
-
使用
app.use()
来定义全局生效的中间件 -
代码如下:
-
// 导入 express 模块 const express = require('express') // 创建 express 的服务器实例 const app = express() // 解析表单数据的中间件 app.use((req, res, next) => { // 定义中间价具体的业务逻辑 }) // 调用 app.listen方法,指定端口号并启动 web 服务器 app.listen(3000, () => { console.log('running……') })
监听 req
的 data
事件
-
在中间件中,需要监听
req
对象的data
事件,来获取客户端发送到服务器的数据 -
如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以
data
事件可能会触发多次,每一次触发data
事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接 -
代码如下:
-
// 导入 express 模块 const express = require('express') // 创建 express 的服务器实例 const app = express() // 解析表单数据的中间件 app.use((req, res, next) => { // 定义中间价具体的业务逻辑 // 1. 定义一个 str 字符串,专门用来存储客户端发送过来的请求体数据 let str = '' // 2. 监听 req 的 data 事件 req.on('data', (chunk) => { str += chunk }) }) // 调用 app.listen方法,指定端口号并启动 web 服务器 app.listen(3000, () => { console.log('running……') })
监听 req
的 end
事件
-
当请求体数据接收完毕之后,会自动触发
req
的end
事件 -
我们可以在
req
的end
事件中,拿到并处理完整的请求体数据 -
代码如下
// 导入 express 模块 const express = require('express') // 创建 express 的服务器实例 const app = express() // 解析表单数据的中间件 app.use((req, res, next) => { // 定义中间价具体的业务逻辑 // 1. 定义一个 str 字符串,专门用来存储客户端发送过来的请求体数据 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方法,指定端口号并启动 web 服务器 app.listen(3000, () => { console.log('running……') })
用 querystring
模块解析请求体数据
-
Node.js
内置了一个querystring
模块,专门用来处理查询字符串。通过这个模块提供的parse()
函数,可以轻松把查询字符串,解析成对象的格式 -
代码如下
// 导入 express 模块 const express = require('express') // 创建 express 的服务器实例 const app = express() // 4. 导入 Node 内置模块 querystring const qs = require('querystring') // 解析表单数据的中间件 app.use((req, res, next) => { // 定义中间价具体的业务逻辑 // 1. 定义一个 str 字符串,专门用来存储客户端发送过来的请求体数据 let str = '' // 2. 监听 req 的 data 事件 req.on('data', (chunk) => { str += chunk }) // 3. 监听 req 的 end 事件 req.on('end', () => { // 在 str 中存放的是完整的请求体数据 console.log(str) // 将字符串格式的请求体数据,解析成对象 // 5. 调用 qs.parse() 方法,将查询字符串解析成对象 const body = qs.parse(str) console.log(body) }) }) app.post('/user', (req, res) => { res.send('ok') }) // 调用 app.listen方法,指定端口号并启动 web 服务器 app.listen(3000, () => { console.log('running……') })
将解析出来的数据对象挂载为 req.body 1. 上游的中间件和下游的中间件及路由之间,共享同一份 req 和 res,因此,我们可以将解析出来的数据,挂载为 req 的自定义属性,命名为 req.body,供下游使用 2. 代码如下
// 导入 express 模块 const express = require('express') // 创建 express 的服务器实例 const app = express() // 4. 导入 Node 内置模块 querystring const qs = require('querystring') // 解析表单数据的中间件 app.use((req, res, next) => { // 定义中间价具体的业务逻辑 // 1. 定义一个 str 字符串,专门用来存储客户端发送过来的请求体数据 let str = '' // 2. 监听 req 的 data 事件 req.on('data', (chunk) => { str += chunk }) // 3. 监听 req 的 end 事件 req.on('end', () => { // 在 str 中存放的是完整的请求体数据 console.log(str) // 将字符串格式的请求体数据,解析成对象 // 5. 调用 qs.parse() 方法,将查询字符串解析成对象 const body = qs.parse(str) // 6. 将解析出来的数据对象挂载为 req.body 属性 req.body = body next() }) }) app.post('/user', (req, res) => { res.send(req.body) }) // 调用 app.listen方法,指定端口号并启动 web 服务器 app.listen(3000, () => { console.log('running……') })
将自定义中间件封装为模块
-
为了优化代码的结构,我们可以把自定义的中间件函数,封装为独立的模块
-
代码如下:
// custom-body-parser.js const qs = require('querystring') const bodyParser = (req, res, next) => { // 定义中间价具体的业务逻辑 // 1. 定义一个 str 字符串,专门用来存储客户端发送过来的请求体数据 let str = '' // 2. 监听 req 的 data 事件 req.on('data', (chunk) => { str += chunk }) // 3. 监听 req 的 end 事件 req.on('end', () => { // 在 str 中存放的是完整的请求体数据 console.log(str) // 将字符串格式的请求体数据,解析成对象 // 5. 调用 qs.parse() 方法,将查询字符串解析成对象 const body = qs.parse(str) // 6. 将解析出来的数据对象挂载为 req.body 属性 req.body = body next() }) } module.exports = bodyParser
// 对自定义的中间件进行模块化拆分 // 导入 express 模块 const express = require('express') // 创建 express 的服务器实例 const app = express() // 1. 导入自己封装的中间件模块 const customBodyParser = require('./017-custom-body-parser') // 2. 将自定义的中间件函数,注册为全局可用的中间件 app.use(customBodyParser) app.post('/user', (req, res) => { res.send(req.body) }) // 调用 app.listen方法,指定端口号并启动 web 服务器 app.listen(3000, () => { console.log('running……') })
时间如白驹过隙,忽然而已,且行且珍惜......