【node.js】express框架中间件中对next函数原理的讨论

一、中间件类型

1、应用程序级中间件

基本用法:挂载于app实例中:


const express = require('express');
let app = express()
app.use(function (req, res, next) {  
console.log('现在时间是:', Date.now())  
next()})
//没有装载路径的中间件功能,每次应用程序收到请求时都会执行该功能。
 
app.use('/user/:id', function (req, res, next) {  
console.log('Req:', req.method)  
next()})
//在 /user/:id 路径上安装的中间件功能。对/user/:id路径上的任何类型的HTTP请求执行该函数。
 
app.get('/user/:id', function (req, res, next) {  
res.send('USER')})

2、路由器级中间件

基本用法:挂载于express.Router()实例中,其他类似于上面

3、错误处理中间件

不同于前面两个,错误处理中间件需要四个参数(err, req, res, next)。必须提供四个参数以将其标识为错误处理中间件函数。即使不需要使用该next对象,也必须指定它以保持签名。该next对象将被解释为常规中间件,并且将无法处理错误。

4、内置中间件

常见的有:

  • express.static提供静态资源,如HTML文件,图像等。
  • express.json使用JSON有效负载解析传入的请求。
  • express.urlencodedURL编码的有效负载解析传入的请求

详见:Express.js express.json() Function - GeeksforGeeks

5、第三方中间件

二、应用程序级和路由级的next函数原理不同

next函数主要负责将控制权交给下一个中间件,如果当前中间件没有终结请求,并且next没有被调用,那么请求将被挂起,后边定义的中间件将得不到被执行的机会。

理论上,所有的中间件在处理控制权交接以及中间件跳转时,都需要调用next。但是,当一个中间件成功处理完请求并返回响应,此时代表中间件终止!不应该再在后面调用next函数,否则会执行没有必要的中间件,导致错误。

例子:

app.get('/a', function(req, res, next) {
    res.send('sucess');
    next();
});

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  console.log(404);
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

//控制台输出内容
404
GET /a 500 6.837 ms - -
Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:345:11)

1、应用程序级next

其next源码如下,可以看出其会遍历堆栈中的中间件,将其做依次匹配,若匹配成功则执行【对于app.use默认匹配路劲是'/',即匹配任何请求】

function next(err) {
    ... //此处源码省略
    // find next matching layer
    var layer;
    var match;
    var route;

    while (match !== true && idx < stack.length) {
      layer = stack[idx++];
      match = matchLayer(layer, path);
      route = layer.route;

      if (typeof match !== 'boolean') {
        // hold on to layerError
        layerError = layerError || match;
      }

      if (match !== true) {
        continue;
      }
      ... //此处源码省略
    }
	... //此处源码省略
    // this should be done for the layer
    if (err) {
        layer.handle_error(err, req, res, next);
    } else {
	    layer.handle_request(req, res, next);
    }
  }

2、路由级next

其执行原理更为简单,如下:

function next(err) {
    if (err && err === 'route') {
      return done();
    }

    var layer = stack[idx++];
    if (!layer) {
      return done(err);
    }

    if (layer.method && layer.method !== method) {
      return next(err);
    }

    if (err) {
      layer.handle_error(err, req, res, next);
    } else {
      layer.handle_request(req, res, next);
    }
  }

它负责同一个路由下多个中间件的控制权的传递,并且它会接收一个参数"route",如果调用next(“route”),则会跳过执行当前的中间件,直接将控制权交给下一个匹配的路由 。

例子:

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

// 中间件1
app.use('/example', (req, res, next) => {
    console.log('Middleware 1');
    next(); // 继续执行下一个中间件或路由处理函数
});

// 中间件2
app.use('/example', (req, res, next) => {
    console.log('Middleware 2');
    next('route'); // 跳过当前中间件,继续执行下一个匹配的路由中间件
});

// 路由处理函数
app.get('/example', (req, res) => {
    console.log('Route Handler');
    res.send('Hello, World!');
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

在这个例子中,当访问 /example 路径时,首先会执行中间件1,然后执行中间件2。在中间件2中,调用 next('route') 会跳过当前中间件,并直接执行路由处理函数。因此,在浏览器中访问 /example 路径时,只会输出 "Route Handler",而不会输出 "Middleware 2"。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

音仔小瓜皮

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

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

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

打赏作者

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

抵扣说明:

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

余额充值