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 博客参考:…

抑郁症中西医治疗对比?

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

矩阵的条件数及病态方程组的处理

对 A x b Axb Axb,如果A或者b有轻微的变动,会使得求解出的 x x x发生巨变,这种矩阵就是病态的 A x b Axb Axb 真实情况 A ( Δ x x ) Δ b b A(\Delta xx)\Delta bb A(Δxx)Δbb 代入误差的扰动情况 Δ x A − 1 Δ b \Delta xA^{-1}\Delta b ΔxA−1Δb 取范数后有 ∣…

人体姿态估计算法

人体姿态估计算法 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 应用程序…

信息学奥赛一本通1190:上台阶

1190&#xff1a;上台阶 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 69016 通过数: 23589 【题目描述】 楼梯有n(0<n<71)阶台阶,上楼时可以一步上1阶,也可以一步上2阶,也可以一步上3阶&#xff0c;编程计算共有多少种不同的走法。 【输入】 输入的每一行…

SCAU:各位数字

各位数字 Time Limit:1000MS Memory Limit:65535K 题型: 编程题 语言: G;GCC 描述 从键盘输入一个3位数的正整数&#xff0c;要求先后输出该数的百位数字与个位数字&#xff0c;各占一行输入格式 一个三位整数输出格式 输出该数的百位数字与个位数字输入样例 123输出…

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

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

迭代器模式-C++实现

题外话&#xff1a; 设计模式是在1994年提出的&#xff0c;当时还没有C的STL库和泛型编程&#xff0c;所以人们为了提供一种有效的方法来访问一个聚合对象&#xff08;例如列表、集合、数组等&#xff09;中的元素&#xff0c;而又不暴露该对象的内部表示&#xff0c;于是想到了…

Pandas在Excel同一个sheet里插入多个Dataframe和行

Pandas默认的to_excel是直接把完成的Datafrme写入一个sheet里,这并不能满足我们在一个sheet里插入多个Dataframe或多行的需求。为了实现插入多行或多Dataframe的目的,我们需要新建一个ExcelWriter对象,然后依次插入数据。 这里我们以插入2个Dataframe和三行单元格为例。 新…

大华技术GIS开发工程师24届秋招三场面试Offer面经

本文介绍2024届秋招中&#xff0c;大华技术股份有限公司的GIS开发工程师岗位的3场面试基本情况、提问问题等。 10月投递了大华技术股份有限公司的GIS开发工程师岗位&#xff0c;所在部门为研发中心。目前完成了一面、二面与三面等全部流程&#xff0c;并有幸获得Offer&#xff…

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…

python-迭代器与生成器

迭代器&#xff08;Iterators&#xff09;和生成器&#xff08;Generators&#xff09;是 Python 中用于处理可迭代对象的重要工具。它们在处理大型数据集或需要逐个产生元素的情况下非常有用。下面是关于这两个概念的中文介绍&#xff1a; 迭代器&#xff08;Iterators&#…

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

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