node.js express路由和中间件

目录

路由

解释

使用方式

中间件

解释

使用方式

中间件类型

路由注册和中间件注册

代码

app全局路由接口请求以及代码解析

示例1

示例2

示例3

示例4

中间件req继承

嵌套子路由

解释

代码

示例1


路由

解释

在 Express 中,路由(Route)用于定义应用程序的端点(URIs)以及如何响应客户端请求。每个端点由一个或多个处理函数(中间件函数)组成,这些函数在匹配的路由上执行。

路由是 Express 应用中一个非常重要的概念,用于组织应用的不同部分,并映射不同的 URL 到相应的处理逻辑。

使用方式

app.use('/api/vi/tours', )app.use('/api/v1/tours', tourRouter); app.use('/api/v1/users', userRouter);app.use('/api/v1/reviews', reviewRouter);app.all('*', (req, res, next) => {next(new AppError(`Can't find ${req.originalUrl} on this server!`, 404));
});

/api/v1/tours、/api/v1/users、/api/v1/reviews * 表示任意路由路径

userRouter、tourRouter、reviewRouter表示将子路由注册为中间件

// tourRoutes.js
// tourRouterconst router = express.Router();router.use('/:tourId/reviews', reviewRouter);router.route('/top-5-cheap').get(tourController.aliasTopTours, tourController.getAllTours);module.exports = router;

中间件

解释

在 Express 框架中,中间件(middleware)是一个函数,它具有访问请求对象(req)响应对象(res),以及应用程序中下一个中间件函数的能力。中间件函数可以执行一系列操作,例如修改请求和响应对象结束请求-响应周期,或者将控制权传递给下一个中间件

使用方式

app.use([path,] callback [, callback...])
app.all([path,] callback [, callback...])

中间件执行流程

中间件类型

express会根据参数数量以及类型判断属于什么中间件类型

内置中间件

app.use(express.json())  // 解析request body

app.use(express.static(`${__dirname}/public`)); // 解析静态资源

...

应用中间件

app.use((req, res, next) => {

  next()

});   // 三个参数

错误处理中间件

app.use((err, req, res, next) => {

  return res.status(errcode).json({

    status: 'error',

  });

});   // 错误处理中间件需要传入4个参数

第三方中间件

const xss = require('xss-clean');  //防止跨站脚本攻击(XSS

const hpp = require('hpp');   //防止 HTTP 参数污染攻击。

const cors = require('cors');   //用于处理跨域请求

const rateLimit = require('express-rate-limit');  //限制请求速率,防止滥用或恶意攻击

const helmet = require('helmet');   //设置各种 HTTP 头来抵御一些常见的 web 安全问题

const morgan = require('morgan');   //记录 HTTP 请求日志

...

app.use(xss())

...

路由中间件

// routes/userRoutes 文件夹

const router = express.Router();  //使用 express.Router() 注册子路由

router.xxx   // router的用法和app完全相同, 具体代码如下

...

// app.js 文件

const userRouter = require('./routes/userRoutes');

app.use('/api/v1/tours', userRouter);  使用app.use注册子路由

...

好了,前面介绍那么多,这只是一个大概的介绍,光看大概是很懵的,最重要的还是直接上代码,查看控制台输出内容,能够更好的理解中间件执行流程。

路由注册和中间件注册

代码

// app.jsconst express = require('express');
const morgan = require('morgan');const childRouter = require('./childRoutes');const app = express();// app.use(middleware)注册全局中间使用app.use
app.use(morgan('dev'));  // 第三方中间件,用于在控制台打印请求日志, 比如:DELETE /api5/2 200 12.226 ms - 22app.use(express.json())  // 内置中间件,解析request bodyapp.use((req, res, next) => {  // 自定义全局中间件req.query.a = 1console.log('全局路由中间件1')next()
});app.use((req, res, next) => {  // 同上console.log(req.query.a)  // 1console.log('全局路由中间件2')next()
});app.use((req, res, next) => {   // app.use 注册中间件可以注册多个console.log('全局路由中间件3')next()
}, (req, res, next) => {console.log('全局路由中间件4')next()
});app.use('/api1', (req, res) => {   // '/api1'指定在什么请求路径上注册中间件,(可能需要在这个路径上做一些安全的校验等等)console.log('全局路由中间件5')return res.status(200).json({ status: 'hello'});
});app.use('/api2', (req, res, next) => {  // 同样可以注册多个中间件console.log('全局路由中间件5')next()
}, (req, res, next) => {console.log('全局路由中间件6')return res.status(200).json({     // 代码顺序从上往下依次执行中间件函数,直到res响应http请求status: 'hello'});
});app.get('/api3/:id', (req, res) => {  // 为指定路径指定get、 post、delete、 patch方法return res.status(200).json({status: 'hello get'});
});app.delete('/api3/:id', (req, res) => {return res.status(200).json({status: 'hello delete'});
});// 同上简写
app.route('/api4/:id') .get((req, res) => {  // 链式判断请求方法 getreturn res.status(200).json({status: 'hello get'});}).delete((req, res) => {  // deletereturn res.status(200).json({status: 'hello delete'});})app.use('/api5', (req, res, next) => {  // 在路径/api3上,注册中间件和子路由childRouter,子路由的用法和全局app上指定路径和注册中间件的语法完全一样console.log(5)next()
}, childRouter);app.all('*', (req, res, next) => { // 如果路由都没命中执行此中间件    * 表示匹配所有路径next(new Error(`Can't find ${req.originalUrl} on this server!`));
});app.use((err, req, res, next) => {return res.status(500).json({status: 'error',});
});app.listen(3000, () => {console.log(`App running on port ${3000}...`);
});

app全局路由接口请求以及代码解析

示例1

请求路由

控制台打印

解释:访问'/api1'路径,执行app.use注册的应用级中间件,最后命中到/api1路径,通过res响应请求。

代码执行流程

示例2

请求路由

控制台打印

解释:如上一样,请求'/api2', 执行app.use注册的应用级中间件,最后命中到/api1路径,通过res响应请求。

代码执行流程

示例3

请求路由

控制台打印

解释:执行过了上面代码注册的全局应用中间件,1 => 2 => 3 => 4, 然后命中api3/:id 这个路由路径(get请求)。

可以通过 app.[method] 注册路由,注册中间件,也可以app.route注册路由,然后链式 .get(middleware).delete(middleware) 为其注册指定请求方式。

代码执行流程

示例4

请求路由

控制台打印

解释:请求/api路径,正常执行完“1 => 2 => 3 => 4”中间件,但是到最后都没有命中这个路由,被app.all注册的路由和中间件捕获,app.all表示能够接受任意请求方式 post、get、delete、patch, " * " 表示任意路径, next一个错误处理, 将处理传递给错误处理中间件,然后res结束请求。

代码执行流程

中间件req继承

中间件的req会被下一个中间req所“继承”,也就是上一个中间件为req设置的值能被下一个req访问

嵌套子路由

解释

Express 中的嵌套路由是指在一个路由处理器中定义另一个路由。这允许你组织和模块化路由的代码,将相关的路由分组在一起,以提高代码的可维护性和可读性。

代码
//childRouterconst express = require('express');
const router = express.Router();router.use((req, res, next) => {  // 自定义子路由中间件console.log('子路由中间件1')next()
});router.use((req, res, next) => {  // 同上console.log('子路由中间件2')next()
});router.use((req, res, next) => {   // router.use 注册中间件可以注册多个console.log('子路由中间件3')next()
}, (req, res, next) => {console.log('子路由中间件4')next()
});router.use('/child-api1', (req, res) => {   // '/api1'指定在什么请求路径上注册中间件,(可能需要在这个路径上做一些安全的校验等等)console.log('子路由中间件5')return res.status(200).json({ status: 'hello child route'});
});router.use('/child-api2', (req, res, next) => {  // 同样可以注册多个中间件console.log('子路由中间件5')next()
}, (req, res, next) => {console.log('子路由中间件6')return res.status(200).json({     // 代码顺序从上往下依次执行中间件函数,直到res响应http请求status: 'hello child route'});
});router.get('/child-api3/:id', (req, res) => {  // 为指定路径指定get、 post、delete、 patch方法return res.status(200).json({status: 'hello get child route'});
});
router.delete('/child-api3/:id', (req, res) => {return res.status(200).json({status: 'hello delete child route'});
});// 同上简写
router.route('/child-api4/:id') .get((req, res) => {  // 链式判断请求方法 getreturn res.status(200).json({status: 'hello get child route'});}).delete((req, res) => {  // deletereturn res.status(200).json({status: 'hello delete child route'});})module.exports = router

子路由注册路由和中间件的方式和app注册的方式完全一样。两边代码对比以下,就会发现完全一样。

示例1

请求路由

控制台打印

解释,在命中/api5这个路由之前,执行以上注册的中间件,打印全局1=>全局2=>全局3=>全局4,然后命中了/api5,打印全局5,然后执行childRouter这个子路由中间件,代码完全如app.js里写的完全一样,依次执行子路由中间件,子1=>子2=>子3=>子4,最后命中/child-api3/:id 这个路由,res响应。

代码执行流程

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

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

相关文章

【Qt开发流程】之事件系统3:键盘事件

序章 以下链接是拖放事件介绍和使用示例: 【Qt开发流程】之拖放操作1:介绍链接: https://blog.csdn.net/MrHHHHHH/article/details/134626484 【Qt开发流程】之拖放操作2:使用链接: https://blog.csdn.net/MrHHHHHH/article/details/134632006 以下链接是事件系统…

百度智能云推出“千帆AI原生应用开发工作台” 助力开发者创新

在这个智能互联的世界,每一次技术的飞跃都预示着无限可能。你是否曾梦想,一款产品能够打破创新的边界,让开发不再是高门槛的技术挑战?12月20日,百度云智大会智算大会将为你揭开这幕神秘面纱——“千帆AI原生应用开发工…

orvibo旗下的VS30ZW网关分析之一

概述 从官网的APP支持的智能中枢来看,一共就两种大类: MixPad系列和网关系列 排除MixPad带屏网关外,剩余的设备如下图: 目前在市场上这四种网关已经下市,官方已经宣布停产。所以市场上流通的也几乎绝迹。 从闲鱼市场上可以淘到几个,拿来分析一下,这里我手头有如下的两…

配置typroa上传图片到gitee

在typora这个位置下载插件 在picgo.exe文件夹下输入cmd 打开命令行输入如下命令安装相关插件 .\picgo install gitee-uploader .\picgo install super-prefix 之后按照官方文档更改相关配置 官方文档参考 https://picgo.github.io/PicGo-Core-Doc 博客参考:…

抑郁症中西医治疗对比?

抑郁症是一种常见的心理障碍,治疗方法包括中医和西医两种。下面就抑郁症中西医治疗进行对比: 治疗方法:中医治疗抑郁症强调整体观念和辨证论治,通过调理身体各部分的功能,达到治疗抑郁症的目的。中医治疗抑郁症多采用天…

人体姿态估计算法

人体姿态估计算法 1 什么是人体姿态估计2 基于经典传统和基于深度学习的方法2.1 基于经典传统的人体姿态估计算法2.2 基于深度学习的人体姿态估计算法OpenPoseAlphaPose (RMPE) 3 算法应用4 Paper 人体姿态估计在现实中的应用场景很丰富,如下 动作捕捉:三…

Android String.xml 设置加粗字体/修改字体颜色/动态设置修改文案

之前经常使用Spannable 这次主要在String.xml使用&#xff1a;<![CDATA[和]]> 效果&#xff1a; <resources><string name"str_bianse"><![CDATA[变色 <font color"#ff0000">曲项向天歌</font> 白毛浮绿水]]></st…

idea新建spring boot starter

什么是spring boot starter Spring Boot Starter 是一种 Maven 或 Gradle 依赖&#xff0c;它能够轻松地将相关库和框架集成到 Spring Boot 应用程序中。Starter 是一种对常见依赖项和设置的易于复用的封装&#xff0c;它们通常被开发人员用于创建可插拔的 Spring Boot 应用程序…

报考公务员简历(精选8篇)

想要成功进入公务员队伍&#xff0c;一份出色的个人简历是必不可少的。本文为大家精选了8篇报考公务员的个人简历案例&#xff0c;无论是应届毕业生还是有工作经验的求职者&#xff0c;都能从中汲取灵感&#xff0c;提升简历质量。找到心仪的公务员岗位。 报考公务员简历模板下…

vite脚手架,手写实现配置动态生成路由

参考文档 vite的glob-import vue路由配置基本都是重复的代码&#xff0c;每次都写一遍挺难受&#xff0c;加个页面就带配置下路由 那就利用 vite 的 文件系统处理啊 先看实现效果 1. 考虑怎么约定路由&#xff0c;即一个文件夹下&#xff0c;又有组件&#xff0c;又有页面&am…

[数据结构]HashSet与LinkedHashSet的底层原理学习心得

我们区分list和set集合的标准是三个&#xff1a;有无顺序&#xff0c;可否重复&#xff0c;有无索引。 list的答案是&#xff1a;有顺序&#xff0c;可重复&#xff0c;有索引。这也就是ArrayList和LinkedList的共性 set的答案是&#xff1a;顺序内部再区分,不可以重复&#xf…

【数电笔记】11-最小项(逻辑函数的表示方法及其转换)

目录 说明&#xff1a; 逻辑函数的建立 1. 分析逻辑问题&#xff0c;建立逻辑函数的真值表 2. 根据真值表写出逻辑式 3. 画逻辑图 逻辑函数的表示 1. 逻辑表达式的常见表示形式与转换 2. 逻辑函数的标准表达式 &#xff08;1&#xff09;最小项的定义 &#xff08;2&am…

【JavaEE】多线程(3) -- 线程等待 wait 和 notify

目录 1. wait()⽅法 2. notify()⽅法 3. notifyAll()⽅法 4. wait 和 sleep 的对⽐&#xff08;⾯试题&#xff09; 由于线程之间是抢占式执⾏的, 因此线程之间执⾏的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执⾏先后顺序. 完成这个协调⼯…

【数电笔记】18-卡诺图化简

目录 说明&#xff1a; 用卡诺图化简逻辑函数 1. 公式法化简与卡诺图化简对比 2. 化简依据 3. 化简规律 3.1 两个小方块相邻 3.2 四个小方块相邻 3.3 八个小方块相邻 4. 卡诺图化简法步骤 4.1 例1 4.2 例2 5. 画卡诺圈规则 5.1 例1 6. 特殊情况 6.1 例1 6.2 例…

【JVM】一篇通关JVM类加载与字节码技术

目录 1. 类文件结构1-1. 魔数 版本 常量池 2. 字节码指令3. 编译期处理4. 类加载阶段5. 类加载器6. 运行期优化 类加载与字节码技术 1. 类文件结构 案例 // HelloWorld 示例 public class HelloWorld {public static void main(String[] args) {System.out.println("h…

[Linux] linux防火墙

一、防火墙是什么 防火墙&#xff08;FireWall&#xff09;&#xff1a;隔离功能&#xff0c;工作在网络或主机的边缘&#xff0c;数据包的匹配规则与由一组功能定义的操作组件处理的规则相匹配&#xff0c;根据特定规则检查网络或主机的入口和出口 当要这样做时&#xff0c;基…

C++函数模板,类模板

C函数模板&#xff0c;类模板 1.函数模板1.1函数模板的概念1.2函数模板的格式1.3函数模板的原理1.4函数模板的实例化1.5模板参数的匹配原则 2.类模板2.1类模板的定义格式2.2类模板的实例化 1.函数模板 1.1函数模板的概念 在C中&#xff0c;函数模板是一种通用的函数定义&…

Linux系统-----进程通讯

前言 本期我们来学习进程间的通讯 一、信号机制 1、信号的基本概念 每个信号都对应一个正整数常量(称为signal number,即信号编号。定义在系统头文件<signal.h>中)&#xff0c;代表同一用户的诸进程之间传送事先约定的信息的类型&#xff0c;用于通知某进程发生了某异常…

Java 使用对应arthas 调试程序

1、作用 使用 arthas 可以进行如下操作 ① 抓取对应函数的耗时结构&#xff0c;然后分析对应的代码优化代码 ② 抓取对应函数的 入参、出参函数 ③ 重放对应的函数执行 ④ 查询对应程序占用结构&#xff0c;比如 cpu, jvm ⑤ 查询对应的 执行最频繁的 线程 ⑥ 打印函数…

开源软件license介绍与检测

开源License介绍 通俗来讲&#xff0c;开源许可证就是一种允许软件使用者在一定条件内按照需要自由使用和修改软件及其源代码的的法律条款。借此条款&#xff0c;软件作者可以将这些权利许可给使用者&#xff0c;并告知使用限制。这些许可条款可以由个人、商业公司或非赢利组织…