Node.js基础---Express中间件

1. 概念

1.什么是中间件

        中间件(Middleware),特指业务流程的中间处理环节

2. Express 中间件的调用流程

        当一个请求到达 Express 的服务器后,可以连续调用多个中间件,从而对这次请求进行预处理

3. Express 中间件格式

       Express 的中间件,本质上是一个 function 处理函数,Express 中间件格式如下

        中间件函数的形参列表中,必须包含 next 参数,而路由处理函数中只包含 req 和 res

4. next 函数的作用

        next 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或者路由

2. 中间件函数

1. 定义

// 常量 mv 所指向的就是一个中间件函数
const mv = function ( req, res, next) {console.log('中间件demo')// 注意: 在当前中间件的业务处理完毕后,必须调用 next() 函数// 表示把流转关系转交给下一个中间件或路由next()
}

2. 全局生效的中间件

        客户端发起的任何请求,到达服务器后,都会触发的中间件,叫全局生效的中间件

        通过调用 app.use(中间件函数),即可定义一个全局生效的中间件

// 常量 mv 所指向的就是一个中间件函数
const mv = function ( req, res, next) {console.log('中间件demo')next()
}// 全局生效的中间件
app.use(mv)

3. 定义全局中间件的简化形式

// 全局生效的中间件
app.use(function (req, res, next){console.log('demo')next()
})

4. 中间件的作用

        多个中间件之间,共享同一份 req 和 res,基于这样的特性,我们可以在上游的中间件中,统一为 req 或 res 对象添加自定义的属性或方法,供下游的中间件或路由进行使用

5. 定义多个全局中间件

        可以使用 app.use() 连续定义多个全局中间件,客户端请求到达服务器后,会按照中间件定义的先后顺序依次进行调用

6. 局部生效的中间件

        不使用 app.use() 定义的中间件,即局部生效的中间件

        只在当前路由生效

const mv1 = function(req, res, next) {console.log('中间件函数')next()
}// mv1 中间件只在当前路由生效
app.get('/', mv1, function(req, res) {res,send('get')
})// 此路由不生效
app.get('/user', function(req, res) {res,send('get1')
})

7. 定义多个局部中间件

        两种等价方式定义

app.get('/', mv1, mv2, function(req, res) { res,send('get') })
app.get('/', [mv1, mv2], function(req, res) { res,send('get') })

8. 中间件的5个使用注意事项

        ①  一定要在路由之前注册中间件

        ②  客户端发送的请求,可以连续调用多个中间件进行处理

        ③  执行完中间件的业务代码,需要调用 next() 函数

        ④  防止代码逻辑混乱,调用完 next() 函数后不要再写额外代码 

        ⑤  连续多个中间件时,多个中间件之间,共享 req 和 res 对象

3. 中间件的分类

        Express 官方把常见的中间件用法,分为了五大类

                ①  应用级别的中间件

                ②  路由级别的中间件

                ③  错误级别的中间件

                ④  Express 内置的中间件

                ⑤  第三方的中间件

1. 应用级别的中间件

        通过 app.use() 或 app.get() 或 app.post()绑定到app实例上的中间件,叫做应用级别的中间件        全局中间件和局部中间件

// 应用级别的中间件 (全局中间件)
app.use((req, res, next) => {next()
})// 应用级别的中间件 (局部中间件)
app.get('/', mv1, (req, res, next) => {res.send('局部')
})

2. 路由级别的中间件 

        绑定到 express.Router() 实例上的中间件,叫做路由级别的中间件,它的用法和应用级别中间件没有区别,区别在于,应用级别中间件是绑定在 app 实例上的,路由级别中间件绑定到 router 实例上的

const app = express()
const router = express.Router()// 路由级别的中间件
router.use(function (req, res, next) {console.log('路由级别中间件')next()
})app.use('/', router)

3. 错误级别的中间件

        作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题

        格式:必须要有 4 个形参,从前到后分别是 (err, req, res, next)

app.get('/', function(req, res) {            // 路由throw new Error('错误!')                 // 抛出自定义错误res.send('get')
})
app.use(function (err, req, res, next) {    // 错误级别的中间件        console.log('发生了错误' + err.message)  // 服务器打印错误消息res,send('Error' + err.message)         // 向客户端响应错误信息相关内容
})

        注意:错误级别的中间件,必须注册在所有路由之后

4. Express内置的中间件

        Express 4.16.0版本后,Express 内置了3个常用的中间件

        ①  express.static 快速托管静态资源的内置中间件,例如:HTML文件,图片,css样式(无兼容性

        ②  express.json 解析JSON格式的请求体数据(有兼容性,在4.16.0+版本可用)

        ③  express.urlencoded 解析 URL-encoded 格式的请求体数据(有兼容性,在4.16.0+版本可用)

// 配置解析 application/json 格式数据的内置中间件
app.use(express.json())
// 配置解析 application/x-www-form-urlencode 格式数据的内置中间件
app.use(express.urlencoded({ extend: false }))

5. 第三方的中间件

        非 Express 官方内置的,是第三方开发出来的中间件,叫第三方中间件,项目中可以按需下载并配置第三方中间件

        在 express@4.16.0 之前的版本中,经常使用 body-parser 第三方中间件来解析请求体数据:

        ①  运行 npm i body-parser 安装

        ②  使用 require 导入中间件

        ③  调用 app.use() 注册并使用中间件

        注意:Express 内置的 express.urlencoded 中间件,就是基于 body-parser 进一步封装的

4.  自定义中间件

1. 需求描述与实现步骤

        需求:手动模拟类似于 express.urlencoded 的中间件,解析POST提交到服务器的表单数据

        实现步骤:

                ①   定义中间件

                ②   监听 req 的 data 事件

                ③   监听 req 的 end 事件

                ④   使用 queryString 模块解析请求体数据

                ⑤   将解析出来的数据对象挂载为 req.body

                ⑥   将自定义中间件封装为模块

2. 定义中间件

        使用 app.use() 定义全局生效的中间件

app.use(function(req, res, next){// 中间件的业务逻辑
})

3. 监听 req 的 data 事件

        获取客户端发送到服务器的数据

        如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以data事件可能会触发多次,每次触发。获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接

// 定义变量 储存客户端发来的请求体数据
let str = ''
// 监听 req 对象的 data 事件
req.on('data', (chunk) => {// 拼接请求体数据,隐式转换为字符串str += chunk
})

4. 监听 req 的 end 事件

        请求体数据接收完毕之后会自动触发 req 的 end 事件

        可以在 req 的 end 事件中,拿到并处理完整的请求体数据

// 监听 req 对象的 end 事件
req.on('end', () => {console.log(str) // 打印完整请求体数据// TOOD: 把字符串的请求体数据,解析成对象格式
})

5. 使用 queryString 模块解析请求体数据

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

// 导入处理 querystring 的 Node.js 内置模块
const qs = require('querystring')// 调用 qs.parse() 方法 把查询字符串解析为对象
const body = qs.parse(str)

        注意:qs被弃用

6. 将解析出来的数据对象挂载为 req.body

        上游中间件和下游中间件及路由之间,共享同一份 req 和 res。可以将解析出来的数据,挂载为 req 的自定义属性,命名为 req.body,供下游使用

req.on('end', () => {const body = qs.parse(srt)    // 调用 qs.parse() 方法把查询字符串解析成对象req.body = body               // 解析出来的请求体对象瓜子next()                        // 调用 next(),执行后续逻辑
})    

7. 将自定义中间件封装为模块

        优化结构,封装为独立模块

// custom-body-parser.js 模块代码
const qs = require('querystring')
function bodyParser(req, res, next){ /* 省略 */ }
module.export = bodyParser // 向外导出解析请求体孙书记的中间件函数---------------------------------------------// 1. 导入自定义的中间件模块
const myBodyParser = require('custom-body-parse')
// 2. 注册自定义的中间件模块
app.use(myBodyParser )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/503743.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于ssm游泳会员管理系统+vue论文

摘 要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统游泳会员信息管理难度大,容错率低&#xff0c…

什么是VR虚拟现实|虚拟科技博物馆|VR设备购买

虚拟现实(Virtual Reality,简称VR)是一种通过计算机技术模拟出的一种全新的人机交互方式。它可以通过专门的设备(如头戴式显示器)将用户带入一个计算机生成的虚拟环境之中,使用户能够与这个虚拟环境进行交互…

【Linux实践室】Linux初体验

🌈个人主页:聆风吟 🔥系列专栏:Linux实践室、网络奇遇记 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 一. ⛳️任务描述二. ⛳️相关知识2.1 🔔Linux 目录结构介绍2.2 🔔Linux …

vue 使用vue-scroller 列表滑动到底部加载更多数据

安装插件 npm install vue-scroller -dmain.js import VueScroller from vue-scroller Vue.use(VueScroller)<template><div class"wrap"><div class"footer"><div class"btn" click"open true">新增</d…

vue2 开发记录

el-select 如何修改选择项的样式/el-select-dropdown__item 文字上下显示 测试代码 <div stylemargin-left: 100px><!-- 测试代码--><el-select filterablesizemini><div classxxx-el-select><el-optionv-foritem in [{key:1,des:2,…

【重温设计模式】装饰模式及其Java示例

装饰模式的介绍 在众多设计模式中&#xff0c;有一种叫做装饰模式&#xff0c;它以一种独特的方式赋予了代码更多的灵活性。 装饰模式是一种结构型设计模式&#xff0c;它允许我们在运行时动态地为对象添加新的行为。这就像是我们在装饰一个房间时&#xff0c;可以随意添加或更…

MySQL进阶之(三)InnoDB数据存储结构之数据页结构

三、InnoDB数据存储结构之数据页结构 3.1 数据库的存储结构3.1.1 MySQL 数据存储目录3.1.2 页的引入3.1.3 页的概述3.1.4 页的上层结构 3.2 数据页结构3.2.1 文件头和文件尾01、File Header&#xff08;文件头部&#xff09;02、File Trailer&#xff08;文件尾部&#xff09; …

构造pop链

反序列化视频笔记 第一步&#xff1a;找到目标触发echo调用$flag 第二步&#xff1a;触发_invoke函数调用appeng函数$varflag.php&#xff08;把对象当成函数&#xff09; 第三步&#xff1a;给$p赋值为对象&#xff0c;即function成为对象Modifier却被当成函数调用&#xff…

c++_leetcode_寻找峰值

目录 一、寻找峰值的示例 二、官方实现代码及解释 1、官方测试结果&#xff1a; 2、代码解释&#xff1a; 3、解题思路&#xff1a; 三、我的暴力解决 1、测试一&#xff1a; 2、测试二&#xff1a; 3、最终“暴力求解”代码&#xff1a; 4、官网提交测试通过&#xf…

《无线网络技术》考试版笔记

第一章 无线网络介绍 什么是多径效应&#xff0c;如何去克服&#xff1a; 在发射机和接收机之间没有明显的直线路径时&#xff0c;就会产生多径传播。如果两个信号彼此叠加&#xff0c;那么接收设备就无法正确解调信号&#xff0c;无法还原为它的原始数据形式。 可以稍微调整接…

实战分享:Tomcat打破双亲委派模型,实现Web应用独立与安全隔离的奥秘

目录 一、JVM 类加载机制 二、Tomcat 类加载器 2.2 findClass 介绍 3.2 loadClass 介绍 三、web应用隔离 3.1 Spring 加载问题 在开始文章内容之前&#xff0c;先来看三个问题 假如在 Tomcat 上运行了两个 Web 应用程序&#xff0c;两个 web 应用中有同名的Servlet&#xf…

腾讯云「2024新春采购节」满额返券,最高返5000元代金券

满额返券 在新春采购节活动上消费满满1万元可返500元代金券、满3万元可返1500元代金券、满6万元可返3000元代金券、满10万元可返5000元代金券&#xff0c;如下图&#xff1a; 腾讯云满额返券 以上是腾讯云百科分享的腾讯云2024年新春采购节优惠活动&#xff0c;更多云服务器详…