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
// tourRouter

const 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.js

const 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 - 22

app.use(express.json())  // 内置中间件,解析request body

app.use((req, res, next) => {  // 自定义全局中间件
  req.query.a = 1
  console.log('全局路由中间件1')
  next()
});

app.use((req, res, next) => {  // 同上
  console.log(req.query.a)  // 1
  console.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) => {  // 链式判断请求方法 get
    return res.status(200).json({
      status: 'hello get'
    });
  })
  .delete((req, res) => {  // delete
    return 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 中的嵌套路由是指在一个路由处理器中定义另一个路由。这允许你组织和模块化路由的代码,将相关的路由分组在一起,以提高代码的可维护性和可读性。

代码
//childRouter

const 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) => {  // 链式判断请求方法 get
    return res.status(200).json({
      status: 'hello get child route'
    });
  })
  .delete((req, res) => {  // delete
    return 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响应。

代码执行流程

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

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

相关文章

【大模型】更强的 ChatGLM3-6B 来了,开源可商用

【大模型】更强的 ChatGLM3-6B 来了,开源可商用 简介ChatGLM3-6B 环境配置环境搭建安装依赖 代码及模型权重拉取拉取 ChatGLM3-6B拉取 ChatGLM3-6B 模型权重及代码 终端测试网页测试安装 gradio加载模型并启动服务 参考 简介 ChatGLM3-6B ChatGLM3-6B 是 ChatGLM …

Python逐步打造惊艳的折线图

大家好,Matplotlib可以快速轻松地使用现成的函数绘制图表,但是微调步骤需要花费更多精力。今天本文将介绍如何使用Matplotlib绘制吸引人的图表,实现折线图的惊艳变身。 1.数据 为了说明方法,本文使用了包含过去50年各国GDP信息的…

短线买入卖出有哪些交易技巧?

前面两节课,我们认识了短线交易,知道了短线交易常见的买入卖出时机,这节课,我们来讲解一下短线买入卖出的一些交易技巧。话不多时,直接进入重点! 一、短线交易要果断 短线波动快,在出现买卖信号…

Redis集群详解

1.1 什么是Redis集群 Redis集群是一种通过将多个Redis节点连接在一起以实现高可用性、数据分片和负载均衡的技术。它允许Redis在不同节点上同时提供服务,提高整体性能和可靠性。根据搭建的方式和集群的特性,Redis集群主要有三种模式:主从复制…

Vue基础知识点梳理

在Vue中,被用来响应地更新HTML属性的指令是v-model页面挂载成功之后会触发哪一个钩子函数mounted挂载之后会进行页面的渲染v-on是动作元素不属于条件渲染指令 在Vue中,下列关于Vue实例对象说法不正确的是()。A.Vue实例对象是通过n…

Spring Cloud NetFlix

文章目录 Spring Cloud1 介绍2 Eureka(服务注册与发现)2.1 介绍2.2 服务注册与发现示例2.2.1 Eureka Server:springcloud-eureka2.2.2 Eureka Client:springcloud-provider2.2.3 Eureka Client:springcloud-consumer 2…

木马病毒是怎么进入服务器的,要如何防范

木马病毒通常是基于计算机网络,基于客户端和服务端的通信、监控程序。名称来源于公元前十二世纪希腊和特洛伊之间的一场战争。能够在计算机管理员未发觉的情况下开放系统权限、泄漏用户信息、甚至窃取整个计算机管理使用权限,隐匿性高。 木马病毒的入侵方…

开关电源的电感选择和布局布线

开关电源(SMPS, Switched-Mode Power Supply)是一种非常高效的电源变换器,其理论值更是接近100%,种类繁多。按拓扑结构分,有Boost、Buck、Boost-Buck、Charge-pump等;按开关控制方式分&#xff…

c语言:整数与浮点数在内存中的存储方式

整数在内存中的存储: 在计算机内存中,整数通常以二进制形式存储。计算机使用一定数量的比特(bit)来表示整数,比如32位或64位。在存储整数时,计算机使用补码形式来表示负数,而使用原码形式来表示…

如何创建一个vue工程

1.打开vue安装网址:安装 | Vue CLI (vuejs.org) 2.创建一个项目文件夹 3.复制地址 4.打开cmd,进入这个地址 5.复制粘贴vue网页的安装命令 npm install -g vue/cli 6.创建vue工程 vue create vue这里可以通过上下键来进行选择。选最后一个选项按回车。 …

企业网盘在医疗行业资料管理中的应用与优势

随着企业网盘的广泛应用,医疗行业正逐渐实现资料安全存储和智能化管理。海量应用的推动下,医院管理正朝着线上化、智能化发展迈进。然而,医疗行业仍面临着诸多挑战。 医疗行业的痛点在于病例、档案、药品资料繁多且保存周期长。这些资料的整理…

L1-009:N个数求和

目录 ⭐题目描述⭐ ⭐分析 ⭐程序代码 运行结果 ⭐文案分享⭐ ⭐题目描述⭐ 本题的要求很简单,就是求N个数字的和。麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式。 输入格式: 输入第一行给出…

XIAO ESP32S3之SenseCraft 模型助手部署

sipeed教程:SenseCraft 模型助手部署 | Seeed Studio Wiki 一、安装ESP-IDF 鉴于我的电脑之前安装过esp-idf v4.3版本,而ESP32-S3需要v4.4及以上版本才支持,所以将esp-idf更新到最新5.1版本。 1、启动mingw32.exe应用 2、进入esp-idf目录 …

前端小记--2.element-ui中级联选择器cascader如何默认展开下拉框

最近做项目时,遇到一个需求:在一个排班表中,展示人员的值班情况,点击单元格,弹出下拉框,修改人员排班信息。 由于下拉框选择内容是树状结构,这里使用了element-ui中级联组件cascader&#xff0c…

ganache部署智能合约报错VM Exception while processing transaction: invalid opcode

这是因为编译的字节码不正确,ganache和remix编译时需要选择相同的evm version 如下图所示: remix: ganache: 确保两者都选择london或者其他evm,只要确保EVM一致就可以正确编译并部署, 不会再出现VM Exception while processing…

Wireshark使用详解

wireshark简介 wireshark是捕获机器上的某一块网卡的网络包,当你的机器上有多块网卡的时候,你需要选择一个网卡。   wireshark能获取HTTP,也能获取HTTPS,但是不能解密HTTPS,所以wireshark看不懂HTTPS中的内容&#…

【C++】类和对象——初始化列表和static修饰成员

首先我们来谈一下初始化列表,它其实是对于我们前边构造函数体内初始化的一种补充,换一种说法,它以后才是我们构造函数的主体部分。 我们先考虑一个问题,就是一个类里面有用引用或const初始化的成员变量,比如说&#xf…

【【FPGA 之 MicroBlaze 自定义IP核 之 呼吸灯实验】】

FPGA 之 MicroBlaze 自定义IP核 之 呼吸灯实验 通过创建和封装 IP 向导的方式来自定义 IP 核,支持将当前工程、工程中的模块或者指定文件目录封装成 IP 核,当然也可以创建一个带有 AXI4 接口的 IP 核,用于 MicroBlaze 软核处理器和可编程逻辑…

kubernetes中YAML介绍;API资源对象Pod;Pod原理和生命周期;Pod资源限制

YAML介绍;API资源对象Pod;Pod原理和生命周期;Pod资源限制 1)认识YAML 官网(https://yaml.org/) YAML 语言创建于 2001 年,比 XML 晚了三年。YAML虽然在名字上模仿了XML,但实质上与…

Spring之RestTemplate详解

Spring之RestTemplate详解 1 RestTemplate1.1 引言1.2 环境配置1.2.1 非Spring环境下使用RestTemplate1.2.2 Spring环境下使用 RestTemplate1.2.3 Spring环境下增加线程号 1.3 API 实践1.3.1 GET请求1.3.1.1 不带参请求1.3.1.2 带参的get请求(使用占位符号传参)1.3.1.3 带参的g…