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 )

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DB-GPT:大模型 + 数据库,全流程自动化

DB-GPT:大模型 数据库,全流程自动化 提出背景DB-GPT 结构具体问题与解法背景分析对比其他工具DB-GPT系统设计 提出背景 论文:https://arxiv.org/pdf/2312.17449.pdf 代码:https://github.com/eosphoros-ai/DB-GPT 本文介绍了D…

Laravel Octane 和 Swoole 协程的使用分析

之前在工作中使用 Laravel Octane 的 concurrently 处理并发时,发现在队列和定时任务中不会触发并发效果。经过分析,作了如下猜测:队列和定时任务都属于一个独立的进程,与 Octane 服务无关,而 Octane concurrently 恰恰…

msvcr120.dll丢失的解决办法,分享解决文件丢失的问题

msvcr120.dll文件丢失有这三种方法可以解决,学会这三种方法的任何一种,以后再出现dll文件丢失的情况都能很好地解决,第一种方法最为简单。先给大家说说msvcr120.dll文件为什么会丢失?丢失的原因是什么? 一.msvcr120.d…

win10安全中心误删文件怎么办?解析恢复与预防策略

在使用Windows 10的过程中,许多用户依赖于其内置的安全中心来保护电脑免受恶意软件的侵害。然而,有时安全中心的误判可能导致重要文件被错误地删除。当面对这种情况时,了解如何恢复误删的文件并掌握预防措施显得尤为重要。本文将为您详细解析…

redis01 基本概念初识

SQL与NOSQL对比 Redis介绍 诞生于2009年,全称是Remote Dictionary Server,远程词典服务器,是一个基于内存的键值型NOSQL数据库。 Redis基本概念 redis为什么快 基于内存(核心),IO多路复用,良…

二百二十五、海豚调度器——用DolphinScheduler调度执行Flume数据采集任务

一、目的 数仓的数据源是Kafka,因此离线数仓需要用Flume采集Kafka中的数据到HDFS中 在实际项目中,不可能一直在Xshell中启动Flume任务,一是项目的Flume任务很多,二是一旦Xshell页面关闭Flume任务就会停止,这样非常不…

if-else 语句

if-else 语句 概念:是双条件分支语句,根据一个条件来控制程 序执行的流程。 语法格式: if(表达式) { 若干语句 } else { 若干语句 }

GEE必须会教程—蒸散发数据时间序列分析与下载

今天带来的有关蒸散发数据的下载代码,蒸散发数据在气象气候,农业干旱监测等领域应用广泛,那么在GEE上如何方便快捷获取蒸散发数据呢?今天跟着小编分享代码,快来学习吧!! A.定义研究区域 //定义…

【C++】类型转换和IO流

目录 C语言中的类型转换 C eplicit && volatitle eplicit volatile C强制类型转换 static_cast(相关类型) reinterpret_cast(不相关类型) const_cast(去掉const属性) dynamic_cast RTTI(了解) IO流 …

ChatGpt 使用fetch-event-source实现sse流式处理

microsoft/fetch-event-source 是一个由微软提供的库,用于在客户端和服务器之间建立基于 EventSource 的连接。EventSource 是一种 HTTP 协议,允许服务器向客户端推送实时事件流。该库提供了对 EventSource 协议的封装,使得在前端 JavaScript…

二维码门楼牌管理系统技术服务:革新城市标识管理的新篇章

文章目录 前言一、二维码门楼牌管理系统的诞生背景二、二维码门楼牌管理系统的技术优势三、二维码门楼牌管理系统的应用前景四、面临的挑战与问题五、结语 前言 在数字化、智能化的时代背景下,二维码门楼牌管理系统作为一种创新的技术服务,正逐渐改变着…

AIGC下一步:如何用AI再度重构或优化媒体处理?

让媒资中“沉默的大多数”再次焕发光彩。 邹娟|演讲者 编者按 AIGC时代下,媒体内容生产领域随着AI的出现也涌现出更多的变化与挑战。面对AI的巨大冲击,如何优化或重构媒体内容生产技术架构?在多样的应用场景中媒体内容生产技术又…

springboot基于web的酒店客房管理系统论文

基于web的酒店客房管理系统 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了酒店客房管理系统的开发全过程。通过分析酒店客房管理系统管理的不足,创建了一个计算机管理酒店客房管理系统的方案。文…

锐捷网络携数据中心、以太全光等创新解决方案亮相2024MWC

在西班牙巴塞罗那举行的2024年世界移动通信大会(MWC)上,锐捷网络(下文简称“锐捷”)展示了将技术与应用充分融合的云数据中心、5G、光网络等产品及解决方案,帮助更多行业组织建设更贴近业务、智能、简单、高效、绿色低碳的网络基础设施,应对当下及未来的挑战,共同连接更广阔可能…

ceph性能测试

查看集群状态 ceph -s查看osd情况 ceph osd tree创建pg_num为60的pool&#xff0c;名为test。 ceph osd pool create test 60rados bench用于测试rados存储池底层性能&#xff0c;该工具可以测试写、顺序读、随机读三种类型 rados bench -p <pool_name> <seconds&…

[物联网] OneNet 多协议TCP透传

[物联网] OneNet 多协议TCP透传 STM32物联网–ONENET云平台的多协议接入产品创建 : https://blog.csdn.net/qq_44942724/article/details/134492924 Onenet tcp 透传 : https://blog.csdn.net/flyme2010/article/details/107086001 tcp服务端测试工具 : http://tcp.xnkiot.com/…

Day12-【Java SE进阶】JDK8新特性:Lambda表达式、方法引用、常见算法、正则表达式、异常

一、JDK8新特性 1.Lambda表达式 Lambda表达式是JDK 8开始新增的一种语法形式;作用:用于简化名内部类的代码写法。 注意:Lambda表达式并不是说能简化全部匿名内部类的写法&#xff0c;只能简化函数式接口的匿名内部类。 有且仅有一个抽象方法的接口。注意:将来我们见到的大部…

IntelliJ IDEA 2023 点击推送至远程仓库发生报错

开始我是直接在IDEA里创建的本地仓库&#xff0c;然后在gitee上的仓库是创建并初始化的&#xff0c;因为你点击初始化后&#xff0c;会默认帮你执行一些代码&#xff0c;然后你再在本地仓库推送至远程仓库就会出现不一致的情况。 当你本地的仓库与远程仓库中的内容不同步时&…

echarts vue 动画效果的水球图、波浪图教程

1、安装插件 前提是已经安装了echarts&#xff08;我的版本是4.2.1&#xff09; npm install echarts-liquidfill --save 我安装了3.1.0版本的&#xff0c;结果运行时报错"TypeError: wave.ensureState is not a function" 原因&#xff1a;echarts版本和echarts-l…

基于JAVA的聊天(ICQ)系统的设计于实现

一、绪论 ICQ是英文"I seek you "的简称&#xff0c;中文意思是我找你。ICQ最大的功能就是即时信息交流&#xff0c;只要记得对方的号码&#xff0c;上网时可以呼他&#xff0c;无论他在哪里&#xff0c;只要他上网打开ICQ&#xff0c;人们就可以随时交流。ICQ源于以…