第三方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-parser
var 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…...

[Deep Learning] 深度学习中常用函数的整理与介绍(pytorch为例)
文章目录 深度学习中常用函数的整理与介绍常见损失函数1. L2_loss | nn.MSELoss()公式表示:特点:应用:缺点:主要参数:示例用法:注意事项: 2. L1 Loss | nn.L1Loss数学定义:特点&…...

【ETCD】etcd简单入门之单节点部署etcd
etcd 是一个分布式可靠的键值存储系统,用于分布式系统中最关键的数据,主要特点包括: 简单:具有明确的、面向用户的 API(gRPC) 安全:自动 TLS 支持,并可选的客户端证书认证 快速&am…...

Cadence基础语法
03-Cadence基础语法 0 Cadence基础语法入门:流程编排语言的新星 Cadence是由Uber开发的一种领域特定语言(Domain-Specific Language,DSL),专门用于编写可扩展的长时间运行的业务流程。它是Temporal工作流引擎的核心组…...

GAMES101虚拟机使用教程与探讨
写在前面 环境配置请参考作业0的pdf,本文章主要对于配置好环境后怎么使用以及遇到的问题进行探讨(要是有更方便的使用方式欢迎在评论区讨论),自己刚开始用的时候也折腾了好久,希望能为后来学习的小伙伴节约一点工具使…...

王道考研编程题总结
我还在完善中,边复习边完善(这个只是根据我自身总结的) 一、 线性表 1. 结构体 #define MaxSize 40 typedef struct{ElemType data[MaxSize];int length; }SqList 2. 编程题 1. 删除最小值 题意 :从顺序表中删除…...

算法2--滑动窗口
滑动窗口 滑动窗口经典例题长度最小的子数组无重复字符的最长子串[最大连续1的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/description/)[将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/description…...

pycharm或conda中配置镜像源
文章目录 1. 为什么要配置镜像源2. pycharm配置2.1使用pip配置国内镜像源2.2 Pycharm中更改镜像源 3.conda配置镜像源3.1 使用conda命令3.2 文件所在位置(进行增删)3.3 conda常用的几个命令 参考文献 1. 为什么要配置镜像源 由于Python在下载包时&#…...

C#基础之方法
文章目录 1 方法1.1 定义方法1.2 参数传递1.2.1 按值传递参数1.2.2 按引用传递参数1.2.3 按输出传递参数1.2.4 可变参数 params1.2.5 具名参数1.2.6 可选参数 1.3 匿名方法1.3.1 Lambda 表达式1.3.1.1 定义1.3.1.2 常用类型1.3.1.3 Lambda 表达式与 LINQ1.3.1.4 Lambda 表达式的…...

JVM 性能调优 -- JVM常用调优工具【jps、jstack、jmap、jstats 命令】
前言: 前面我们分析怎么去预估系统资源,怎么去设置 JVM 参数以及怎么去看 GC 日志,本篇我们分享一些常用的 JVM 调优工具,我们在进行 JVM 调优的时候,通常需要借助一些工具来对系统的进行相关分析,从而确定…...

PostgreSQL 三种关库模式
PostgreSQL 三种关库模式 基础信息 OS版本:Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本:16.2 pg软件目录:/home/pg16/soft pg数据目录:/home/pg16/data 端口:5777PostgreSQL 提供了三种关库模式&…...