Node.js--》如何在Node.js中使用中间件,看这一篇就足够了

news2024/9/28 1:23:13

目录

中间件

中间件函数使用

中间件的作用

中间件分类

使用中间件的注意事项

编写接口

跨域问题及其解决方案


中间件

中间件特指业务流程的中间处理环节。当一个请求到达 Express 的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。

Express的中间件,本质上就是一个 function 处理函数,Express 中间件的格式如下:

注意:中间件函数的形参列表中,必须包含 next 参数。而路由处理函数中只包含req和res。

next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。

中间件函数使用

const express = require('express')
const app = express()

// 定义一个最简单的中间件函数
const thing = function(req,res,next){
  console.log('这是最简单的中间件函数');
  // 把流转关系,转交给下一个中间件或路由
  next()
}

app.listen(80,()=>{
  console.log('express server running at http://127.0.0.1');
})

全局生效的中间件:客户端发起的任何请求,到达服务器之后,都会触发中间件,叫做全局生效的中间件。通过调用 app.use(中间件函数) ,即可定义一个全局生效的中间件,如下:

const express = require('express')
const app = express()

// 定义一个最简单的中间件函数
const thing = function(req,res,next){
  console.log('这是最简单的中间件函数');
  // 把流转关系,转交给下一个中间件或路由
  next()
}

// 将 thing 注册为全局生效的中间件
app.use(thing)

app.get('/',(req,res)=>{
  console.log('调用了 / 这个路由');
  res.send('Home page')
})
app.get('/user',(req,res)=>{
  res.send('User page')
})

app.listen(80,()=>{
  console.log('express server running at http://127.0.0.1');
})

先将请求交给中间件,中间件执行过后,把流转关系转交给下一个中间件或路由。

全局中间件简化形式:我们注册全局中间件时也可以采用简化形式。

// 定义一个简化的中间件函数
app.use(function(req,res,next){
  console.log('这是最简单的中间件函数');
  // 把流转关系,转交给下一个中间件或路由
  next()
})

定义多个全局中间件:可以使用 app.use() 连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用。

局部生效中间件:不使用 app.use() 定义的中间件,叫做局部生效的中间件,如下:

const express = require('express')
const app = express()

// 定义局部生效中间件
const thing = (req,res,next)=>{
  console.log('调用了局部生效中间件');
  next()
}

// 定义路由
app.get('/',thing,function(req,res){
  res.send('Home page')
})
app.get('/user',function(req,res){
  res.send('User page')
})

app.listen(80,()=>{
  console.log('express server running at http:127.0.0.1');
})

定义多个局部中间件:可以在路由中,通过如下两种方式使用多个局部中间件:

// 使用局部中间件的两种方法
app.use('/',w1,w2,w3,(req,res)=>{ res.send('Home page') })
app.use('/',[w1,w2,w3],(req,res)=>{ res.send('Home page') })

中间件的作用

多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req和res对象添加自定义属性方法,供下游的中间件或路由进行使用。

中间件分类

Express官方把常见的中间件用法,分成了如下五大类:

应用级别的中间件:通过app.use() 或 app.get() 或 app.post() ,绑定到 app 实例上的中间件,叫做应用级别的中间件,案例如下:

// 应用级别的中间件(全局中间件)
app.use((req,res,next)=>{ 
  next()
})
// 应用级别的中间件(局部中间件)
app.get('/',w1,function(req,res){
  res.send('Home page')
})

路由级别的中间件:绑定到 express.Router() 实例上的中间件,叫做路由级别的中间件。它的用法和应用级别的中间件没有任何区别,只不过一个是绑定到app实例上,另一个是绑定到router实例上,案例如下:

// 导入 express 模块
const express = require('express')
var app = express()
// 创建路由对象
const router = express.Router()

// 路由级别的中间件
router.use(function(req,res,next){
  next()
})
app.use('/',router)

错误级别的中间件:作用是专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题,其格式:错误级别的中间件的function处理函数中,必须有四个参数,形参顺序从前往后分别是(err,req,res,next)。注意:错误级别的中间件,必须注册在所有路由之后!

// 定义路由
app.get('/',(req,res)=>{
  throw new Error('服务器发生异常!') // 人为制造错误
  res.send('Home page')
})
// 定义错误级别的中间件,捕获整个项目的异常错误,从而防止程序的奔溃
app.use((err,req,res,next)=>{
  console.log('发生了错误'+err.message);
  res.send('Error: '+err.message)
})

Express内置的中间件:自 Express 4.16.0 版本开始,Express内置了3个常用的中间件。极大的提高了Express项目的开发效率和体验:

1)express.static 快速托管静态资源的内置中间件,例如:HTML文件、图片、CSS等,之前文章已经讲解过,这里不再赘述,详情请看:express.static文章讲解

2)express.json 解析 JSON 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可以)

// 通过 express.json() 这个中间件,解析表单中的 JSON 格式的数据
app.use(express.json())
// 定义路由
app.post('/user',function(req,res){
  // 在服务器中,可使用req.body属性来接收客户端发送过来的请求体数据
  // 默认情况下,如果不配置解析表单数据的中间件,则req.body默认等于undefined
  console.log(req.body);
  res.send('ok')
})

3)express.urlencoded 解析 URL-encoded 格式的请求体数据(有兼容性,仅在4.16.0+版本可用)

const express = require('express')
const app = express()

// 通过 express.urlencoded() 这个中间件,解析表单中的 url-encoded 格式的数据
app.use(express.urlencoded({extended: false}))
// 定义路由
app.post('/book',function(req,res){
  // 在服务器中,可使用req.body属性来接收客户端发送过来的 JSON或url-encoded格式的数据
  console.log(req.body);
  res.send('ok')
})

app.listen(80,()=>{
  console.log('express server running at http:127.0.0.1');
})

第三方的中间件:非Express官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件,在项目中,可以按需下载和配置第三方中间件,从而提高项目的开发效率。案例如下:

安装第三方中间件:npm i body-parser

使用中间件的注意事项

1)一定要在路由之前注册中间件

2)客户端发送过来的请求,可以连续调用多个中间件进行处理

3)执行完中间件的业务代码之后,不要忘记调用next()函数

4)为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码

5)连续调用多个中间件时,多个中间件之间,共享 req和res对象

编写接口

编写GET接口,如下:

const express = require('express')
// 导入第三方中间件
const app = express()

// 导入路由模块
const router = require('./router')
// 将路由模块注册到app上
app.use('/api',router)

app.listen(80,()=>{
  console.log('express server running at http:127.0.0.1');
})
const express = require('express')
const router = express.Router()

// 挂载对应路由
router.get('/get',(req,res)=>{
  // 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
  const query = req.query
  // 通过 res.send() 方法,向客户端响应处理的结果
  res.send({
    status:0, // 0 表示处理成功,1表示失败
    msg:'GET请求成功', // 状态描述
    data:query // 需要响应给客户端的数据
  })

})

module.exports = router

编写POST接口,如下:

router.post('/post',(req,res)=>{
  // 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
  const body = req.body
  // 通过 res.send() 方法,向客户端响应处理的结果
  res.send({
    status:0, // 0 表示处理成功,1表示失败
    msg:'POST请求成功', // 状态描述
    data:body // 需要响应给客户端的数据
  })
})

跨域问题及其解决方案

我们在编写的GET和POST接口,可能存在一个问题,不支持跨域请求,也就是说不能在file协议中去编写POST和GET请求。解决跨域问题的方案有两种:CORS(主流的解决方案,推荐使用);JSONP(有缺陷的解决方案,只支持GET请求)。

CORS:Cross-Origin Resource Sharing,跨域资源共享。由一系列HTTP响应体组成,这些HTTP响应头决定浏览器是否阻止前端JS代码跨域获取资源。

CORS注意事项

1)CORS主要在服务器端进行配置,客户端浏览器无需做任何的额外的配,即可请求开启了CORS的接口。

2)CORS在浏览器中有兼容性,只支持 XMLHttpRequest Level2 的浏览器,才能正常访问开启了CORS的服务端口

cors是Express的一个第三方中间件,通过安装和配置cors中间件,可以很方便的解决跨域问题。

安装cors中间件命令: npm install cors

// 在路由之间配置 cors 这个中间件,从而解决接口跨域问题
const cors = require('cors')
app.use(cors())

配置CORS响应头

响应头中可以携带一个 Access-Control-Allow-Origin 字段,如语法如下:

// 第二个参数指定了允许访问该资源外域的URL,如想访问所有域的请求,可用通配符 * 
res.setHeader('Access-Control-Allow-Origin','http://www.baidu.com')

响应头中可以携带一个 Access-Control-Allow-Headers 字段,如语法如下:

// 如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过 Access-Control-Allow-Headers 对额外的请求头进行声明,否则会失败!
res.setHeader('Access-Control-Allow-Headers','Context-Type, X-Custom-Header')

响应头中可以携带一个 Access-Control-Allow-Methods 字段,如语法如下:

// 默认情况下,CORS仅支持客户端发起GET,POST,HEAO请求
// 如果客户端希望通过PUT,DELETE等方式请求服务器资源,则需要在服务器端,通过Access-Control-Allow-Methods来指明实际请求所允许的HTTP方法
res.setHeader('Access-Control-Allow-Methods','POST,GET,DELETE,HEAD')
// 允许所有 HTTP 方法
res.setHeader('Access-Control-Allow-Methods','*')

CORS请求的分类

客户端在请求CORS接口时,根据请求方式和请求头的不同,可以将CORS的请求分为两大类:

简单请求

预检请求:在浏览器与服务器正式通信之前,浏览器会先发送ОPTION请求进行预检,以获知服务器是否允许该实际请求,所以这一次的OPTION请求称为“预检请求”。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。

简单请求和预检请求的区别:

简单请求的特点:客户端与服务器之间只会发生一次请求。

预检请求的特点:客户端与服务器之间会发生两次请求,OPTION预检请求成功之后,才会发起真正的请求。

创建JSONP接口

浏览器端通过<script>标签的src属性,请求服务器上的数据,同时服务器返回一个函数的调用,这种请求数据的方式叫做JSONP

如果项目中已经配置了CORS跨域资源共享,为了防止冲突,必须在配置CORS中间件之前声明JSONP的接口,否则JSONP接口会被处理成开启了CORS的接口。案例如下:

// 必须在配置 cors 中间件之前,配置 JSONP 接口
app.get('/api/jsonp',(req,res)=>{
  // 得到函数名称
  const funcname = req.query.callback
  // 定义要发送到客户端的数据对象
  const data = {name:'zs',age:18}
  // 拼接出一个函数声明
  const scriptStr = `${funcname}(${JSON.stringify(data)})`
  // 把拼接的字符串响应给客户端
  res.send(scriptStr)
})

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

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

相关文章

【网络排查】用于接口不通,mysql,kafka等数据库介质连不上的排查

这篇文章记录生产实践中遇到的网络不通的例子 文章目录前言1. 网络协议1.1 应用层找到有问题的服务端 IP总结前言 接口调用不同了了怎么办&#xff1f; 就找接口服务提供方&#xff0c;肯定是提供方的问题的&#xff0c;跟调用方有啥关系~ kafka&#xff0c;mysql等数据库介质…

JAVAGUI编程初识之Swing

文章目录一 常用窗口1.1 JFrame框架窗口1.2 演示-JFRame,JLable的使用1.3 JDialog标签1.3.1 演示-JDialog标签二 标签组件2.1 标签2.2 图标2.2.1 ICon接口简介2.2.2 演示-用Icon接口创建图标2.3 图片图标2.3.1 演示-图片图标三 布局管理器3.1 绝对布局3.1.1 绝对布局简介3.1.2 …

年末再看指针。看来搞C/C++,如影随形的指针就得门清~~~

继上篇博文因内核页表引出的指针问题&#xff0c;后来又研究了一番&#xff0c;这次应该比较清楚了&#xff0c;这里再总结一下。 目录 0 前言 1 普通指针&#xff1a; 2 指针的指针&#xff1a; 3 普通指针参数&#xff1a; 4 指针的指针参数&#xff1a; 5 函数指针&a…

[Kettle] 认识Kettle

1.初识Kettle Kettle是ETL数据整合与处理工具&#xff0c;翻译成中文是"水壶"的意思&#xff0c;可理解为希望把各种数据放到一个壶里&#xff0c;像水一样以一种指定的格式流出&#xff0c;表达数据流的含义 ETL(Extract - Transform - Load)是将数据从数据来源端…

centos7部署rancher2.5

一、 什么是 Rancher Rancher 是为使用容器的公司打造的容器管理平台。Rancher 简化了使用 Kubernetes 的流程&#xff0c;开发者可以随处运行 Kubernetes&#xff08;Run Kubernetes Everywhere&#xff09;&#xff0c;满足 IT 需求规范&#xff0c;赋能 DevOps 团队。 Ran…

单纯形法与对偶单纯形法的通俗理解

cigma<0,a>0 min cigma/(a) 决定出基变量 1对偶单纯形法 意思是看c就是所有货物的价值&#xff0c;去看一眼这些货物单价组合售卖的价值&#xff0c;这些价值肯定要都大于0&#xff0c;而且&#xff0c;组成这个c的系数也应该是都是正的&#xff0c; c最小证明对min&a…

港科夜闻|香港科大-越秀集团百万奖金国际创业大赛2022年度前8强20强项目评审结果公布...

关注并星标每周阅读港科夜闻建立新视野 开启新思维1、“香港科大-越秀集团”百万奖金国际创业大赛2022年度前8强&20强项目评审结果公布。2022年赛事中的各赛区前三名项目&#xff0c;共计23个项目自动入围年度总决赛&#xff0c;本轮评审在这23个项目中&#xff0c;评选出了…

Hudi学习02 -- Hudi核心概念

文章目录基本概念时间轴&#xff08;Timeline&#xff09;文件布局&#xff08;File Layout&#xff09;索引&#xff08;Index&#xff09;索引原理索引类型索引的选择策略表类型&#xff08;Table Types&#xff09;查询类型&#xff08;Query Types&#xff09;写操作&#…

Qt第五十二章:Qt Design Studio使用技巧。

一、运行项目和Debugging项目【快捷键&#xff1a;CtrR】 二、 预览单Qml文件 三、添加资源文件 &#xff08;使用资源&#xff1a;将资源拖动到Editor中的矩形中即可&#xff09; 四、多状态【正常状态、按下状态、划过状态、已点击状态...】 注意&#xff1a;多状态看起来像…

java短网址平台

git地址 Reduce: 短网址平台&#xff0c;Coody Framework首秀&#xff0c;自写IOC、MVC、ORM、TASK、JSON、DB连接池、服务器。百毫秒启动&#xff0c;全项目仅2.1M&#xff08;低配服可运行&#xff09; reduce短网址平台 测试站地址&#xff1a;http://dev.icoody.cn/ 技…

DOM事件

鼠标事件监听 键盘事件监听 表单事件监听 常见的页面事件监听 事件传播 事件传播顺序&#xff1a;从内到外&#xff08;冒泡阶段&#xff09;onxxx这样写法只能监听冒泡阶段 addEventListener()方法第三个参数如果为true监听捕获阶段&#xff0c;false监听冒泡阶段(默认) 最…

C语言及算法设计课程实验二:数据类型、运算符和简单的输入输出

C语言及算法设计课程实验二&#xff1a;数据类型、运算符和简单的输入输出一、实验目的二、实验内容2.1、输入并运行教材第3章第4题给出的程序&#xff1a;2.2、输入第3章第5题的程序2.3、输入以下程序&#xff1a;2.4、程序设计题&#xff1a;假如我国国民生产总值的年增长率为…

遗传算法解决函数优化问题

遗传算法解决函数优化问题 作者: Cukor丘克环境: MatlabR2020a vscode 为什么要学习遗传算法 为什么要学习遗传算法&#xff0c;或者说遗传算法有什么厉害的地方。例如求解以下函数优化问题&#xff1a;minf(x1,x2)x12x1225∗(sin2x1sin2x2),−10≤x1≤10,−10≤x2≤10.min…

【ACWING】【图的深度优先遍历】【846树的重心】

给定一颗树&#xff0c;树中包含 n个结点&#xff08;编号 1∼n&#xff09;和 n−1条无向边。 请你找到树的重心&#xff0c;并输出将重心删除后&#xff0c;剩余各个连通块中点数的最大值。 重心定义&#xff1a;重心是指树中的一个结点&#xff0c;如果将这个点删除后&…

js复习之正则表达式正向肯定与否定预查询

正则表达式(regular expression)描述了一种字符串匹配的模式&#xff08;pattern&#xff09;&#xff0c;可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。 正则表达式_百度百科 除开常用基本匹配模式&#xff0c;偶尔也会用到…

回顾艰难且不失温度的 2022 年 | 文中附「双12免单王」获奖名单

今天是 2022 年最后一天&#xff0c;回忆往昔&#xff0c;这一年经历了太多的不可思议和无可奈何之事。在年末的短短几周&#xff0c;寒气长驱直下以惊人的速度传给每一个人。我们真诚地希望大家都可以平安渡过这一难关。 即使步步难行&#xff0c;亦要踱步前行&#xff01;无…

力扣刷题记录——190. 颠倒二进制位、191. 位1的个数、202. 快乐数

本专栏主要记录力扣的刷题记录&#xff0c;备战蓝桥杯&#xff0c;供复盘和优化算法使用&#xff0c;也希望给大家带来帮助&#xff0c;博主是算法小白&#xff0c;希望各位大佬不要见笑&#xff0c;今天要分享的是——《190. 颠倒二进制位、191. 位1的个数、202. 快乐数》。 目…

Gradle学习笔记之依赖

文章目录依赖的方式直接依赖项目依赖本地jar包依赖依赖的类型api和implementation的区别依赖冲突及解决方案移除某个依赖不允许依赖传递强制使用某个版本依赖冲突时立刻构建失败依赖的方式 Gradle中的依赖方式有直接依赖、项目依赖和本地jar包依赖三种&#xff1a; dependenc…

【一起从0开始学习人工智能0x02】字典特征抽取、文本特征抽取、中文文本特征抽取

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录什么是特征工程&#xff1f;用什么做&#xff1f;1.特征提取特征值化&#xff1a;特征提取API字典特征提取---向量化---类别--》one-hot编码哑变量one-hot-------直接1234会产生歧义&#xff0c;不公平应用场…

Python 10k+ 面试试题,看看你是否掌握

前言 大家早好、午好、晚好吖 ❤ ~ 面试实战题&#xff1a;采集世界最大旅游平台Tripadvisor 另我给大家准备了一些资料&#xff0c;包括: 2022最新Python视频教程、Python电子书10个G &#xff08;涵盖基础、爬虫、数据分析、web开发、机器学习、人工智能、面试题&#xff…