第三方Express 路由和路由中间件
文章目录
- 1、Express 应用使用回调函数的参数: request 和 response 对象来处理请求和响应的数据。
- 2、Express路由
- 1.路由方法
- 2.路由路径
- 3.路由处理程序
- 3. 模块化路由
- 4. Express中间件
- 1.中间件简介
- 2.中间件分类
- 3.自定义中间件
1、Express 应用使用回调函数的参数: request 和 response 对象来处理请求和响应的数据。
- Request 对象
request 对象表示 HTTP 请求,包含了请求查询字符串,参数,内容,HTTP 头部等属性属性/方法 说明 app 当callback为外部文件时,用req.app访问express的实例 baseUrl 获取路由当前安装的URL路径 body/cookies 获得「请求主体」/ Cookies fresh/stale 判断请求是否还「新鲜」 hostname/ip 获取主机名和IP地址 originalUrl 获取原始请求URL params 获取路由的parameters path 获取请求路径 protocol 获取协议类型 query 获取URL的查询参数串 route 获取当前匹配的路由 subdomains 获取子域名 accepts() 检查可接受的请求的文档类型 acceptsCharsets/acceptsEncodings/acceptsLanguages 返回指定字符集的第一个可接受字符编码 get() 获取指定的HTTP请求头 is() 判断请求头Content-Type的MIME类型 - Response 对象
response 对象表示 HTTP 响应,即在接收到请求时向客户端发送的 HTTP 响应数据属性/方法 说明 app 当callback为外部文件时,用req.app访问express的实例 append() 追加指定HTTP头 set() 在res.append()后将重置之前设置的头 res.cookie(name,value [,option]) 设置Cookie opition domain / expires / httpOnly / maxAge / path / secure / signed clearCookie() 清除Cookie download() 传送指定路径的文件 get() 返回指定的HTTP头 json() 传送JSON响应 jsonp() 传送JSONP响应 location() 只设置响应的Location HTTP头,不设置状态码或者close response redirect() 设置响应的Location HTTP头,并且设置状态码302 render(view,[locals],callback) 渲染一个view,同时向callback传递渲染后的字符串,如果在渲染过程中有错误发生next(err)将会被自动调用。callback将会被传入一个可能发生的错误以及渲染后的页面,这样就不会自动输出了。 send() 传送HTTP响应 sendFile(path [,options] [,fn]) 传送指定路径的文件 -会自动根据文件extension设定Content-Type set() 设置HTTP头,传入object可以一次设置多个头 status() 设置HTTP状态码 type() 设置Content-Type的MIME类型
2、Express路由
路由是指应用程序的终端节点 (URI) 如何响应客户端请求。
在Express中,路由指的是客户端的请求与服务器处理函数之间的映射关系。
Express中的路由分3部分组成,分别是请求的类型、请求的URL地址、处理函数,格式如下:app.method(path, handler)
1.路由方法
// GET method route
app.get('/', function (req, res) {res.send('GET request')
})// POST method route
app.post('/', function (req, res) {res.send('POST request')
})
app.all() 用于在所有 HTTP 请求方法的路径上加载中间件函数。
无论是使用 GET、POST、PUT、DELETE 还是 http 模块中支持的任何其他 HTTP 请求方法,都会对路由 “/secret” 的请求执行以下处理程序。
app.all('/secret', function (req, res, next) {console.log('all')next() // pass control to the next handler
})
2.路由路径
路由路径可以是字符串、字符串模式或正则表达式。
// acd和abcd
app.get('/ab?cd', function (req, res) {res.send('ab?cd')
})




总结:问号前面字符可有可无
app.get('/ab(cd)?e', function (req, res) {res.send('ab(cd)?e')
})



总结:问号前面括号内的字符可有可无
app.get('/ab+cd', function (req, res) {res.send('ab+cd')
})





总结:加号前面字符可无限叠加
app.get('/ab*cd', function (req, res) {res.send('ab*cd')
})



总结:星号前面的字符为开始,后边的字符为结束字符,中间可以任意字符或数字
app.get(/a/, function (req, res) {res.send('/a/')
})


总结:满足正则/a/的都满足此方法
app.get(/.*fly$/, function (req, res) {res.send('/.*fly$/')
})


总结:满足正则/.*fly$/以fly字符结束的路由
3.路由处理程序
在没有理由继续当前路由时将控制权传递给后续路由。next(‘route’)
路由处理程序可以采用函数、函数数组或两者的组合形式。
-
单个回调函数可以处理路由。
var express = require('express'); var app = express(); app.get('/abc', function (req, res) {res.send('hello abc'); }) app.listen(8081, function () {console.log("服务启动") }) -
多个回调函数可以处理一个路由(确保指定对象)next();
var express = require('express'); var app = express(); app.get('/abc', function (req, res, next) {console.log(111)next() }, function(req, res) {res.send('hello abc next'); }) app.listen(8081, function () {console.log("服务启动") })

-
回调函数数组可以处理路由。
var express = require('express'); var app = express(); var a0 = function (req, res, next) {console.log('A0')next() } var a1 = function (req, res, next) {console.log('A1')next() } var a2 = function (req, res) {res.send('Hello from A!') } app.get('/abc', [a0, a1, a2]) app.listen(8081, function () {console.log("服务启动") })

-
独立函数和函数数组的组合可以处理路由。
var express = require('express'); var app = express(); var a1 = function (req, res, next) {console.log('A1')next() } var a2 = function (req, res) {res.send('Hello from A!') } app.get('/abc', function (req, res, next) {console.log('A0')next() },[a1, a2]) app.listen(8081, function () {console.log("服务启动") })

3. 模块化路由
为了方便对路由进行模块化的管理,Express不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。
将路由抽离为单独模块的步骤如下:
1.创建路由模块对应的.js文件
2.调用express.Router()函数创建路由对象
3.向路由对象上挂载具体的路由
4.使用module.exports向外共享路由对象
5.使用app.use()函数注册路由模块
- 创建路由模块
// router.js 文件 var express = require('express'); // 1.导入express var router = express.Router(); // 2.创建路由对象router.get('/login/info', (req, res) => { // 3.挂载登录用户信息res.send('Get user list.'); }); router.post('/singUp/add', (req, res) => { // 4.挂载注册用户的路由res.send('Add new user.'); }); module.exports = router; // 5.向外导出路由对象 - 注册路由模块
const express = require('express'); const app = express(); // 1.导入路由模块 const userRouter = require('./router.js'); // 2.使用app.use()注册路由模块 app.use(userRouter); app.listen(8081, () => {console.log('http://127.0.0.1') }) - 为路由模块添加前缀
// 类似于托管静态资源时,为静态资源统一挂载访问前缀一样 // 1.导入路由模块 const userRouter = require('./router.js'); // 2.使用app.use()注册路由模块,并添加统一的范围前缀 /api app.use('/api', userRouter);
4. Express中间件
1.中间件简介
- 中间件简介
中间件是一种特殊的路由处理函数,它可以在请求到达目标处理函数之前,进行一些预处理操作。Express 支持使用中间件来实现各种功能,例如身份验证、请求日志记录,处理 CORS(跨源资源共享)等。
注意:中间件函数的形参列表中,必须包含next参数,而路由处理函数中只包含req和res。
next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
可以使用app.use()连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用const express = require('express'); const app = express(); // 一个简单的中间件 app.use((req, res, next) => {console.log(`Request received at ${new Date()}`);next(); // 将控制权传递给下一个中间件或路由处理器 }); // 一个路由处理器,用于处理 GET 请求 app.get('/', (req, res) => {res.send('Hello, World!'); });// 启动服务器 app.listen(8081, () => {console.log('Server is running on port 8081'); });
- 局部中间件
不使用app.use()定义的中间件,叫做局部生效的中间件, 中间件只在"当前路由中生效",var express = require('express'); var app = express();var myLogger = function (req, res, next) {console.log('LOGGED')next() } app.get('/', myLogger, function (req, res) {res.send('Hello World!') })
- 中间件的5个使用注意事项
- 一定要在路由之前注册中间件
- 客户端发送过来的请求,可以连续调用多个中间件进行处理
- 执行完中间件的业务代码之后,不要忘记调用next()函数
- 为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码
- 连续调用多个中间件时,多个中间件之间,共享req和res对象
- 监听 req 的 data 事件
在中间件中,需要监听req对象的data事件,来获取客户端发送到服务器的数据。
如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以data事件可能会触发多次,每一次触发data事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。// 定义变量,用来储存客户端发送过来的请求体数据 let str = '' // 监听 req 对象的 data 事件(客户端发送过来的新的请求体数据) req.on('data',(data) => {// 打印请求数据console.log(data) }) - 监听 req 的 end 事件
当请求体数据接收完毕之后,会自动触发req的end 事件。
可以在req的end 事件中,拿到并处理完整的请求体数据。// 监听 req 对象的 end 事件(请求体发送完毕后自动触发) req.on('end',() => {// => 打印完整的请求体数据console.log(str)// TODO: 业务逻辑// ....... })
2.中间件分类
- 应用程序级中间件
通过app.use()或app.get()或 app.post(),绑定到app实例上的中间件,叫做应用级别的中间件,var app = express(); var myLogger = function (req, res, next) {console.log('LOGGED')next() } // 应用级别的中间件(全局中间件) app.use((req, res, next) => {req.name = 'router'req.on('end',() => {console.log('end')})next(); }); // 应用级别的中间件(局部中间件) app.get('/', myLogger, (req, res) => {console.log(req.name)res.send('Home page.') }); app.listen(8081, function () {console.log("服务启动") })
- 路由器级中间件
绑定到express.Router()实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不过,应用级别中间件是绑定到 app实例上,路由级别中绚件摸定到router 实例上var express = require('express') var app = express() var router = express.Router() router.use(function (req, res, next) {console.log('Time:', Date.now());next() }) app.use('/', router) app.listen(8081, function () {console.log("服务启动") })
- 错误处理中间件
错误处理中间件是专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
格式:错误级别的中间件的 function 处理函数中,必须有 4 个形参,形参顺序从前到后,分别是(err,req,res,next)。
注意:错误级别的中间件,必须注册在所有路由之后app.get('/', (req, res) => { // 1.路由throw new Error('服务器内部发生了错误'); // 1.1.抛出一个自定义的错误res.send('Home Page.'); }); app.use((err, req, res, next) => { // 2.错误级别的中间件console.log('发生了错误:' + err.message); // 2.1.在服务器打印错误消息res.send('Erroe!' + err.message); // 2.2.向客户端响应错误相关的内容 }); - 内置中间件
三个内置的中间件分别是
express.static 是快速托管静态资源的内置中间件 例如:HTML文件、图片、CSS样式等(无兼容性)
express.json是拿来解析json格式数据的
express.urlencoded是拿来解析urlencoded格式数据的var express = require('express'); var app = express(); // 注意这是中间件 所以必须配置到路由之前 app.use(express.json()) app.use(express.urlencoded({extended : false})) app.listen(8081, function () {console.log("服务启动") }) - 第三方中间件
非Express官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中,大家可以按需下载并配置第三方中间件,从而提高项目的开发效率。
安装所需功能的 Node.js 模块,然后在应用程序级别或路由器级别将其加载到应用程序中。
以cookie-parser为示例:$ npm install cookie-parservar express = require('express') var app = express() var cookieParser = require('cookie-parser') app.use(cookieParser())
3.自定义中间件
自定义中间件步骤:
- 定义中间件
- 监听req的data事件
- 监听req的end事件
- 使用querystring模块解析请求体数据
- 将解析出来的数据对象挂载为req.body
- 将自定义中间件封装为模块
// myparse.js //1.1 导入内置模块 const qs=require('querystring') //1.2 编写解析函数 function myparse(req,res,next){//2.2 定义一个变量存储客户端字符串let str=''//2.1 对客户端请求数据的监听//注意是对客户端对象进行监听,而不是服务器req.on('data',(chunk)=>{str+=chunk})//2.4 进行发送数据结束的监听req.on('end',()=>{//倘若有响应,说明数据发送结束,我们已经拿到所有数据console.log(str)//4.2 利用内置模块的parser()进行数据解析const body=qs.parse(str)//4.3 进行数据对象的挂载req.body=bodyconsole.log(body)})//2.5 不要忘记需要调用next函数next() } //1.4 通过module.exports暴露 module.exports = myparse// 使用 var express = require('express'); var app = express(); // 2.1 导入自定义解析模块 const myparse = require('./mybody-parse') app.use(myparse) app.get('/login', function (req, res) {console.log(req.body);res.end(req.body); })
相关文章:
第三方Express 路由和路由中间件
文章目录 1、Express 应用使用回调函数的参数: request 和 response 对象来处理请求和响应的数据。2、Express路由1.路由方法2.路由路径3.路由处理程序 3. 模块化路由4. Express中间件1.中间件简介2.中间件分类3.自定义中间件 1、Express 应用使用回调函数的参数&am…...
七、Python —— 元组、集合和字典
文章目录 一、元组1.1、元组的初始化1.2、元组的解包1.3、元组的比较运算1.4、元组的其他操作 二、集合 set2.1、集合的初始化2.2、集合的常用操作2.3、使用 for 循环遍历集合 三、字典 map3.1、字典的初始化3.2、字典的常用操作3.3、使用 for 循环遍历字典 四、补充 一、元组 …...
Aes加解密
加解密概念 加密AES加密填充模式加密模式示例 加密 通过一系列计算将明文转换成一个密文。 加密和解密的对象通常是字节数组(有的语言动态数组类比切片) 加密后的数据,可能有很多是不可读字符。通常会将其转换为可见的字符串。 直接将字节…...
【时时三省】Tessy 故障入侵 使用教程
目录 1,故障入侵 介绍 故障入侵适用场景: 打故障入侵的方法和选项介绍: 2,打单个函数的故障入侵 3,打整体用例的故障入侵 4,一个函数打多个故障入侵 山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 1,故障入侵 介绍 故障入侵适用场景: 故障入侵 …...
.NET 9 AOT的突破 - 支持老旧Win7与XP环境
引言 随着技术的不断进步,微软的.NET 框架在每次迭代中都带来了令人惊喜的新特性。在.NET 9 版本中,一个特别引人注目的亮点是 AOT( Ahead-of-Time)支持,它允许开发人员将应用程序在编译阶段就优化为能够在老旧的 Win…...
CondaValueError: Malformed version string ‘~‘: invalid character(s).
问题描述:在window下使用conda安装任何包都会报错。报错信息是CondaValueError: Malformed version string ~: invalid character(s). 解决办法:把.condarc文件的源地址删除(八成是源地址访问不了了),只保存默认的&am…...
01-Ubuntu24.04LTS上安装PGSQL
目录 一、准备工作 1.1、系统要求 1.2 、更新 Ubuntu 系统 1.3 、安装依赖 1.4 、添加 PostgreSQL 16 软件源 二、安装 PostgreSQL 16 数据库 三、管理 PostgreSQL 服务 四、PostgreSQL 管理操作 4.1 、访问 Postgres 超级用户账户 4.2 、创建数据库并设置管理权限 4…...
Esp32使用micropython基于espnow实现语音对讲机
ESP-NOW协议介绍 ESP-NOW 是乐鑫自主研发的无连接通信协议,具有短数据包传输功能。该协议使多个设备能够以简单的方式相互通信。ESP-NOW 支持以下功能: 加密和未加密的单播通信; 混合加密和未加密的对等设备; 最多可携带 250 字节 的有效载荷; 发送回调功能,可以设置用于…...
Docker 容器隔离关键技术:SELinux
Docker 容器隔离关键技术:SELinux SELinux(Security-Enhanced Linux) 是 Linux 内核中的一项安全机制,用于实现强制访问控制(MAC)。Docker 利用了 SELinux 来增强容器的隔离性,通过对文件、进程…...
Java并发07之ThreadLocal
文章目录 1 ThreadLocal原理2 内部结构3 内存泄露问题4 entry的key为什么被设计为弱引用 1 ThreadLocal原理 ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private st…...
【单细胞数据库】癌症单细胞数据库CancerSEA
数据库地址:home (hrbmu.edu.cn) Cite Huating Yuan, Min Yan, Guanxiong Zhang, Wei Liu, Chunyu Deng, Gaoming Liao, Liwen Xu, Tao Luo, Haoteng Yan, Zhilin Long, Aiai Shi, Tingting Zhao, Yun Xiao, Xia Li, CancerSEA: a cancer single-cell state atlas…...
Rsa加解密 + 签名验签
Rsa加解密 概述聚合算法名称(用于创建加密器)基本概念填充方式分块加密 基本使用生成密钥加解密创建加密器设置模式(加密)、公钥对明文加密,并对结果进行Base64编码对以上结果,进行解密 设置模式࿰…...
bugku-web-留言板1
大小写绕过也不行 <ScRipt>ALeRt(“XSS”);</sCRipT> 双写绕过可以 <scscriptript>alert(z)</scscriptript> 改变大小写 在测试过程中,我们可以改变测试语句的大小写来绕过XSS规则: 比如:<script>alert(“xs…...
进程状态的学习
进程状态就是 task_struct 内的一个整数 状态间是可以进行转化的 运行: 每一个框都是进程的task_struct,都有唯一的pcb和pid来标识它的唯一性 让CPU选择一个进程去运行,本质是选择一个进程的PCB去运行,task_struct里一定有内存指…...
Vue 2.0->3.0学习笔记(Vue 3 (四)- Composition API 的优势)
Vue 2.0->3.0学习笔记(Vue 3 (四)- Composition API 的优势) Composition API 的优势1. Options API 存在的问题2. Composition API 的优势 Composition API 的优势 1. Options API 存在的问题 笔记 使用传统OptionsA…...
close and shutdown?
背景:我们要讲述的是网络编程中常用的两个API: #include <unistd.h> int close(int fd); #include <sys/socket.h> int shutdown(int sockfd, int how); 以及TCP的半连接,半打开。 shutdown函数的行为依赖第二个参数区分…...
PostgreSQL + hasura + Apollo + GraphQL + React + Antd
技术栈 PostgreSQL hasura Apollo GraphQL React Antd 适用于复杂的查询,快速开发 环境安装 安装PostgreSQL hasura,使用docker安装 使用 Docker Compose 部署时,它会同时启动两个容器PostgreSQL和 Hasura GraphQL ,如下 version: "3.6" serv…...
Android笔记【10】
一、前言 学习课程时,对于自己不懂的点的记录。 二、内容 学习一段代码: val drawerState rememberDrawerState(DrawerValue.Closed)val scope rememberCoroutineScope()Scaffold (topBar{TopAppBar(navigationIcon {IconButton(onClick {scope.lau…...
Leetcode打卡:N皇后
执行结果:通过 题目:51 N皇后 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#…...
Linux内核4.14版本——ccf时钟子系统(3)——ccf一些核心结构体
目录 1. struct clk_hw 2. struct clk_ops 3. struct clk_core 4. struct clk_notifier 5. struct clk 6. struct clk_gate 7. struct clk_divider 8. struct clk_mux 9. struct clk_fixed_factor 10. struct clk_fractional_divider 11. struct clk_multiplier 12…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
