node.js express路由和中间件

news2025/2/25 3:07:43

目录

路由

解释

使用方式

中间件

解释

使用方式

中间件类型

路由注册和中间件注册

代码

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响应。

代码执行流程

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

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

相关文章

Spring | Spring的基本应用

目录: 1.什么是Spring?2.Spring框架的优点3.Spring的体系结构 (重点★★★) :3.1 Core Container (核心容器) ★★★Beans模块 (★★★) : BeanFactoryCore核心模块 (★★★) : IOCContext上下文模块 (★★★) : ApplicationContextContext-support模块 (★★★)SpE…

Linux中文件的打包压缩、解压,下载到本地——zip,tar指令等

目录 1 .zip后缀名: 1.1 zip指令 1.2 unzip指令 2 .tar后缀名 3. sz 指令 4. rz 指令 5. scp指令 1 .zip后缀名: 1.1 zip指令 语法:zip [namefile.zip] [namefile]... 功能:将目录或者文件压缩成zip格式 常用选项&#xff1a…

《YOLOv8原创自研》专栏介绍 CSDN独家改进创新实战专栏目录

YOLOv8原创自研 https://blog.csdn.net/m0_63774211/category_12511737.html?spm1001.2014.3001.5482 💡💡💡全网独家首发创新(原创),适合paper !!! 💡&a…

QT 中 QProgressDialog 进度条窗口 备查

基础API //两个构造函数 QProgressDialog::QProgressDialog(QWidget *parent nullptr, Qt::WindowFlags f Qt::WindowFlags());QProgressDialog::QProgressDialog(const QString &labelText, const QString &cancelButtonText, int minimum, int maximum, QWidget *…

java源码-类与对象

1、类与对象的初步认知 在了解类和对象之前我们先了解一下什么是面向过程和面向对象。 1)面向过程编程: C语言就是面向过程编程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。 2)面向对…

【数据结构】最短路径(Dijskra算法)

一.引例 计算机网络传输的问题: 怎样找到一种最经济的方式,从一台计算机向网上所有其他计算机发送一条消息。 抽象为: 给定带权有向图G(V,E)和源点v,求从v到G中其余各顶点的最短路径。 即&…

23.Python 图形化界面编程

目录 1.认识GUI和使用tkinter2.使用组件2.1 标签2.2 按钮2.3 文本框2.4 单选按钮和复选按钮2.5 菜单和消息2.6 列表框2.7 滚动条2.8 框架2.9 画布 3. 组件布局4.事件处理 1.认识GUI和使用tkinter 人机交互是从人努力适应计算机,到计算机不断适应人的发展过程&#…

Redis中的数据结构

文章目录 第1关:Redis中的数据结构 第1关:Redis中的数据结构 这是上篇文章的第一关,只不过本篇是代码按行做的,方便一下大家使用。 代码如下: redis-cliset hello redislpush educoder-list hellorpush educoder-lis…

cmake和vscode 下的cmake的使用详解(三)

第七讲:【实战】使用 VSCode 进行完整项目开发 案例:士兵突击 需求: 1. 士兵 许三多 有一把 枪 ,叫做 AK47 2. 士兵 可以 开火 3. 士兵 可以 给枪装填子弹 4. 枪 能够 发射 子弹 5. 枪 能够 装填子弹 ——…

初识RocketMQ

1、简介 RocketMQ 是阿里巴巴在 2012 年开源的消息队列产品,用 Java 语言实现,在设计时参考了 Kafka,并做出了自己的一些改进,后来捐赠给 Apache 软件基金会,2017 正式毕业,成为 Apache 的顶级项目。Rocket…

canvas基础:绘制贝塞尔曲线

canvas实例应用100 专栏提供canvas的基础知识,高级动画,相关应用扩展等信息。 canvas作为html的一部分,是图像图标地图可视化的一个重要的基础,学好了canvas,在其他的一些应用上将会起到非常重要的帮助。 文章目录 bez…

pygame实现贪吃蛇小游戏

import pygame import random# 游戏初始化 pygame.init()# 游戏窗口设置 win_width, win_height 800, 600 window pygame.display.set_mode((win_width, win_height)) pygame.display.set_caption("Snake Game")# 颜色设置 WHITE (255, 255, 255) BLACK (0, 0, 0…

docker容器内部文件挂载主机

docker images执行该命令可以发现一个centos镜像 docker run --namemycentos -itd --privilegedtrue --restartalways -p 88:80 -v C:\Users\Administrator\Desktop\dockerTest:/bin/gh:ro centosdocker run 命令用于在 Docker 上创建和运行容器。 --namemycentos 指定容器…

SHAP(四):NHANES I 生存模型

SHAP(四):NHANES I 生存模型 这是一个 Cox 比例风险模型,基于来自 NHANES I 的数据以及来自 NHANES I 流行病学随访研究。 它旨在说明 SHAP 值如何能够以传统上仅由线性模型提供的清晰度解释 XGBoost 模型。 我们在数据中看到有趣…

JDK17的安装与配置

JDK17的安装与配置 下载地址安装步骤配置环境变量验证安装是否成功 下载地址 此jdk17安装的系统是win10系统 https://www.oracle.com/java/technologies/downloads/ 这里选择JDK17进行下载 下载完成之后,显示如下图: 安装步骤 自定义的安装路径&…

【从删库到跑路 | MySQL总结篇】事务详细介绍

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】🎈 本专栏旨在分享学习MySQL的一点学习心得,欢迎大家在评论区讨论💌 目录 一、事务…

多项式拟合求解

目录 简介 基本原理 例1 例2 例3 参考资料 简介 多项式拟合可以用最小二乘求解,不管是一元高阶函数,还是多元多项式函数,还是二者的混合,都可以通过统一的方法求解。当然除了最小二乘法,还是其他方法可以求解&…

分享一个国内可用的免费GPT4-AI提问AI绘画网站工具

一、前言 ChatGPT GPT4.0,Midjourney绘画,相信对大家应该不感到陌生吧?简单来说,GPT-4技术比之前的GPT-3.5相对来说更加智能,会根据用户的要求生成多种内容甚至也可以和用户进行创作交流。 然而,GPT-4对普…

【尾递归】

尾递归 如果函数在返回前才进行递归调用,则该函数可以被编译器或解释器优化,使其在空间效率上与迭代相当。这种情况被称为「尾递归 tail recursion」。 普通递归:当函数返回到上一层级的函数后,需要继续执行代码,因此…

CookieSession Redis 到JWT会话管理历史

单应用时期,通常使用 Cookies 和 Session 进行会话管理。 用户登录后,服务器创建一个唯一的会话标识符(Session ID),将其存储在浏览器的 Cookies 中,并在服务端维护一个关联该标识符的会话对象。 这种方…