express中间件原理(app.use())

1.什么是中间件

中间件就是一个请求处理方法,用其把用户从请求到响应的整个过程分发到多个中间件去处理,这样做的目的是提高代码的灵活性,动态可扩展的。简单的理解就是:将收到的请求进行逐层过滤。

2.express中的中间件

请求处理的过程是:当服务器接收到请求之后,如果服务器写了多个中间件,则按照顺序依次匹配,直到匹配到符合要求的中间件,然后进行处理。需要注意的是:同一个请求所经过的中间件都是同一个请求对象和响应对象

中间件分类:

  1. 应用程序级别中间件

    • 全匹配(不关心任何请求路径和请求方法,当用户请求的时候如果分发到该中间件则直接进行处理请求操作)

      app.use(function (req,res,next) {
              
              
        console.log('全匹配');
        next();
      })
      

      当请求经过这个中间件的时候,不关心请求路径和方法,直接进入该中间件进行处理。其中next是一个方法,用于调用下一个符合条件的中间件。如果不写next,则会在当前中间件停留下来,不会再去匹配其他中间件。

    • 路径以/xx/开头的匹配(模糊匹配)

      app.use('/a',function (req,res,next) {
              
              
        console.log(3333);
      })
      

      只有以/a/开头的路径才可以匹配成功并处理,比如:/a/b是可以匹配成功的,但是/ab/b不能匹配成功

  2. 路由级别中间件(精确匹配)

    必须与请求路径和请求方法一致才匹配成功

    app.get('/a',(req,res) => {
          
          
      console.log(1111);
      res.send('index.html');
    })
    

next使用:

  • 没有参数

查看以下场景:

app.use(function (req,res,next) {
    
    
  console.log('全匹配');
  next();
})

app.use('/a',function (req,res,next) {
    
    
  console.log(3333);
  next();
})

app.get('/a',(req,res) => {
    
    
  console.log(1111);
  res.render('index.html');
})

app.get('/',(req,res) => {
    
    
  console.log('2222');
  res.render('index.html',{
    
    
    name: 'chen'
  })
})

app.get('/',(req,res) => {
    
    
  console.log('44444');
})

浏览器输入url127.0.0.1:3000/依次遍历每个中间件,匹配到第一个完全匹配的中间件,打印出全匹配之后,调用了next,然后继续去匹配符合要求的中间件,遇到第二个全匹配中间件不符合以/a/开头的路径,则直接掠过,继续匹配第三个,由于是精确匹配,仍然匹配不成功,当遇到最后一个中间件的时候,匹配成功,输出2222,可以看出next查找的条件一直都是浏览器请求对象,也即需要符合127.0.0.1:3000/这个请求。

再来另一个场景:

app.get('/a',(req,res,next) => {
    
    
  console.log(1111);
  next();
})
app.get('/a',(req,res) => {
    
    
  res.send('ok');
})

当访问/a时,匹配到第一个中间件输出1111,遇到next,匹配到第二个中间件,返回客户端ok,可以看出,请求匹配中间件是逐一匹配的过程,而不是后者覆盖前者的一个过程。

  • 带有参数

    app.use(function (req,res,next) {
          
          
      console.log('全匹配');
      let err = '出错了';
      next(err);
    })
    
    app.use('/a',function (req,res,next) {
          
          
      console.log(3333);
      next();
    })
    
    # 带有四个参数,且这四个参数必须写全
    app.use(function (err,req,res,next) {
          
          
      console.log(err);// 出错了
    })
    

    当访问/a路径的时候,匹配到第一个中间件,遇到next,并且带有参数,则不会再去匹配其他的中间件,直接去带有四个参数的中间件去匹配,可以用于统一处理错误响应

使用第三方插件的原理:

由于:同一个请求所经过的中间件都是同一个请求对象和响应对象,所以当一个中间件在请求对象上添加其他内容之后,其他被匹配成功的中间件可以访问到这个新增的内容,例如:

# 访问'/'
app.use(function (req,res,next) {
    
    
  console.log(111);
  req.body = {
    
    
    name: 'chen'
  }
  next()
})

app.use('/',function (req,res,next) {
    
    
  console.log(req.body.name);// chen
})

以上代码就展示了当匹配到第一个中间件的时候,在请求对象上新增了body属性,然后调用第二个匹配的中间件的时候,可以访问到新增的属性内容。而第三方插件也就是这种方式,修改请求对象并返回相应的内容,当访问其他中间件的时候,就可以访问到第三方插件新增的内容,比如:body-parser插件

# 假设已经下载好了body-parser插件
# 引入包
const bodyParser = require('body-parser');
# 将body-parser函数作为参数传递到app.use中
app.use(bodyParser.urlencoded({
    
    extended: false}));
app.use(bodyParser.json());

app.get('/',(req,res)=> {
    
    
    console.log(req.body);
})

当将bodyParser作为函数传入中间件时,此时会对请求对象进行添加body属性等操作,添加完成之后,务必会调用next,然后继续匹配下一个中间件,此时在精确匹配中间件中就可以使用body属性了。

从以上一系列的使用过程中,可以看出,中间件书写顺序还是影响请求响应的。

3.总结

中间件作为请求的一种过滤手段,其中express中的中间件中主要依赖于next连接多个中间件,同时由于:同一个请求所经过的中间件都是同一个请求对象和响应对象,使得多个中间件之间可以进行通信。

实际应用:

  • 采用中间件根据需求配置插件
  • 对统一请求进行过滤之后再处理请求
  • 对于出错响应可以进行统一处理操作

猜你喜欢

转载自blog.csdn.net/chen__cheng/article/details/115072038