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

目录

中间件

中间件函数使用

中间件的作用

中间件分类

使用中间件的注意事项

编写接口

跨域问题及其解决方案


中间件

中间件特指业务流程的中间处理环节。当一个请求到达 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)
})
  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 16
    评论
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亦世凡华、

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值