express中间件


Express 基于 Connect 构建而成,因此,它也保持了重用中间件来完成基础任务的想法。这就意味着,通过 Express 的 API 方便地构建 Web 应用地同时,又不失构建于 HTTP 模块之上高可用中间件地生态系统。

中间件

由于 Express 是构建于 Connect 之上地,所以,当创建 Express 服务器时可以使用 Connect 兼容地中间件。比如,要托管 image/ 目录下的图片,就可以像这样使用 static 中间件

app.use(express.static(__dirname + '/images'))

注意了,在引入了 Express 之后就可以直接使用 Connect 的中间件了。不需要 require(‘connect’)或者把 connect 作为项目依赖添加到 package.json 文件中。

定义一个最简单的中间件

Express 中间件本质上就是一个 function 处理函数,其具体结构如下:

在这里插入图片描述
这个 next() 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或者路由。

// 定义一个最简单的中间件
const mw = (req,res,next)=>{
	console.log('这是最简单的一个中间件')
	// 把流转关系,转交给下一个中间件或者是路由
	next()
}

自定义中间件

  1. 定义中间件
  2. 监听 req 的 data 事件
  3. 监听 req 的 end 事件
  4. 使用 querystring 模块解析请求体数据
  5. 讲解洗出来的数据对象挂载为 req.body
  6. 将自定义中间件封装为模块

下面我们手动模拟一个类似于 express.urlencoded 这样的中间件,来解析 POST 提交到服务器的表单数据。

首先我们定义一个全局中间件

const express = require('express')
const app = express()
// 这是解析表单数据的中间件
app.use((req, res, next) => {
	//定义中间件具体的业务逻辑
})
app.listen(80,()=>{
	console.log('Express server running at http://127.0.0.1')
})

第二步我们来编写监听 req 的 data 事件的代码
在中间件中,需要监听 req 对象的 data 事件,来获取客户端发送到服务器的数据。
如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以 data 事件可能会触发多次,每一次触发
data 事件时,获取到数据只是完整数据的一部分,需要手动对接受到的数据进行拼接。
代码如下:

// 1、定义一个 str 字符串,专门用来存储客户端发送过来的请求体数据
let str = ''
// 2、监听 req 的 data 事件
req.on('data', (chunk) => {
	str += chunk
})

第三步我们来编写监听 req 的 end 事件的代码
当请求体数据接收完毕之后,会自动触发 req 的 end 事件。
因此,我们可以在 req 的 end 事件中,拿到并处理完整的请求体数据。
代码如下:

// 3、监听 req 的 end 事件
req.on('end', () => {
	//在 str 中存储的就是完整的请求体数据
	console.log(str)
	// TODO: 把字符串格式的请求体数据,解析成对象格式
})

使用 querystring 模块解析请求体数据
Node.js 中内置了一个 querystring 模块,专门用来处理查询字符串。通过这个模块提供的 parse() 函数,可以轻松把查询字符串,解析成对象的格式。

//导入 querystring 模块
const qs = require('querystring')

req.on('end', () => {
	const body = qs.parse(str)
	console.log(body)
})

第四步将解析出来的数据对象挂载为 req.body
上游的中间件和下游的中间件以及路由之间,共享用一份 req 和 res。因此,我们可以将解析出来的数据挂在为 req 的自定义属性,命名为 req.body ,供下游使用。
在 end 中写进代码:

req.on('end', () => {
	const body = qs.parse(str)
	console.log(body)
	req.body = body
	next()
})

并且将 res.send('ok') 更改成 res.send(req.body)

最后一步将自定义中间件封装为模块
为了优化代码的结构,我们可以把自定义的中间件函数,封装为独立的模块。
先定义一个常量将 res.use() 内的内容封装起来,然后再向外导入
代码如下:

const bodyParser = ((req, res, next) => {
	//...
})
module.exports = bodyParser

完整代码

// 导入 querystring 模块
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 中存储的就是完整的请求体数据
		// TODO: 把字符串格式的请求体数据,解析成对象格式
		const body = qs.parse(str)
		req.body = body
		next()
	})
})
module.exports = bodyParser

至此,自定义一个中间件已经全部完成,现在只需要在 test.js 中进行导入就可使用。
测试代码如下:

const express = require('express')
const app = express()
//导入自己封装好的中间件模块
const customBody = require('./类urlencoded的中间件')
//将自定义的2中间件函数,注册成为全局可用的中间件
app.use(customBody)
app.post('/book',(req,res)=>{
	res.send(req.body)
})
app.listen(80,()=>{
	console.log('Express server running at http://127.0.0.1')
})

中间件的五个使用注意事项

  1. 一定要在路由之前注册中间件
  2. 客户端发送过来的请求,可以连续调用多个中间件进行处理
  3. 执行完中间件的业务代码之后,不要忘记调用 next() 函数
  4. 为了防止代码逻辑混乱,调用 next() 函数后不要再写额外的代码
  5. 连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上行舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值