Node.js - 关于 express 中间件(中间件的简单使用)

835 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情

什么是中间件

中间件是指业务流程的中间处理环节


Express 中间件的调用流程

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

Snip20220402_9.png

Express 中间件的格式

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

    app.get('/',function(req,res,next)){
        next();
    }
    
  • 中间件函数的形参列表中,必须包含 next 参数,而路由处理函数中只包含 resreq


next 函数的作用

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

Snip20220402_9.png


定义中间件函数

在当前中间件的业务处理完毕后,必须调用 next() 函数,表示把流转关系转交给下一个中间件或路由

const mw = function (req, res, next) {
    console.log('这是一个 中间件')
    
    //业务处理。。。
    
    next()
}

全局生效的中间件

  • 客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫作全局生效中间件

  • 通过调用 app.use(中间件函数) ,即可定义一个全局生效的中间件

  • 示例

    const express = require('express')
    const app = express()
    
    const mw = function (req, res, next) {
        console.log('这是一个 中间件')
        next()
    }
    
    // 将 mw 注册为全局生效的中间件
    app.use(mw)
    
    app.listen(80, ()=> {
        console.log('express 服务器运行在 http://127.0.0.1.80')
    })
    

    log:

    Snip20220408_10.png

  • 定义全局中间件的简化形式

    app.use(function (req, res, next) {
        console.log('这是一个 中间件')
        next()
    })
    

定义多个全局中间件

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

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

app.use(function (req, res, next) {
    console.log('调用了第1个全局中间件')
    next()
})

app.use(function (req, res, next) {
    console.log('调用了第2个全局中间件')
    next()
})

app.get(`/`, (req, res) => {
    res.send('home page ')
})

app.listen(80, ()=> {
    console.log('express 服务器运行在 http://127.0.0.1.80')
})

log:

Snip20220408_11.png


局部生效的中间件

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

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

// 定义一个中间件函数
const mw1 = function(req, res, next) {
    console.log('这是中间件函数')
    next()
}

// mw1 中间件只会在当前路由中生效
app.get('/', mw1, function(req, res){
    console.log('经过中间件')
    console.log('home pag')
    res.send('home page')
})

// mw1 中间件不会影响这个路由
app.get('/user', function(req, res){
    console.log('不经过中间件')
    console.log('user page')
    res.send('user page')
})

app.listen(80, ()=> {
    console.log('express 服务器运行在 http://127.0.0.1.80')
})

log:

Snip20220408_12.png


定义多个局部中间件

  • 在路由中,可以使用多个局部中间件,以下俩种方式等价

    app.get('/', mw1,mw2, (req, res) => {
    
    })
    
    app.get('/', [mw1,mw2], (req, res) => {
    
    })
    
  • 示例

    const express = require('express')
    
    const app = express()
    
    const mw1 = function(req, res, next) {
        console.log('第1个中间件函数')
        next()
    }
    
    const mw2 = function(req, res, next) {
        console.log('第2个中间件函数')
        next()
    }
    
    app.get('/', mw1,mw2, (req, res) => {
        console.log('home page')
        res.send('home page')
    })
    
    app.listen(80, ()=> {
        console.log('express 服务器运行在 http://127.0.0.1.80')
    })
    

    log:

    Snip20220409_13.png


中间件的作用

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

  • 示例(获取每次请求到达的时间)

    • 不使用中间件,每个路由都需添加时间

      const express = require('express')
      const app = express()
      
      app.use(function (req, res, next) {
          next()
      })
      
      app.get(`/`, (req, res) => {
          // 添加时间
          const time = Date.now()
          res.send('home page ' + time)
      })
      
      app.get(`/user`, (req, res) => {
          // 添加时间
          const time = Date.now()
          res.send('user page ' + time)
      })
      
      app.listen(80, ()=> {
          console.log('express 服务器运行在 http://127.0.0.1.80')
      })
      
    • 使用中间件,统一在中间件中添加时间

      const express = require('express')
      const app = express()
      
      app.use(function (req, res, next) {
      
          const time = Date.now()
          // 为 req 对象挂载自定义属性,从而把时间共享给后面的所有路由
          req.startTime = time
          
          next()
      })
      
      app.get(`/`, (req, res) => {
          res.send('home page ' + time)
      })
      
      app.get(`/user`, (req, res) => {
          res.send('user page ' + time)
      })
      
      app.listen(80, ()=> {
          console.log('express 服务器运行在 http://127.0.0.1.80')
      })
      

中间件的5个使用注意事项

  • 一定要在路由之前注册中间件
  • 客户端发送过来的请求,可以连续调用多个中间件进行处理
  • 执行完中间件的业务代码之后,不要忘记调用 next() 函数
  • 为了防止代码逻辑混乱,调用 next() 函数后不要再写额外的代码
  • 连续调用多个中间件时,多个中间件之间,共享 reqres 对象