zoukankan      html  css  js  c++  java
  • express函数参数之next

     
    关于next主要从三点来进行说明:
     
    1. next的作用是什么?
    2. 我们应该在何时使用next?
    3. next的内部实现机制是什么?
     
     
    1.Next的作用
    我们在定义express中间件函数的时候都会将第三个参数定义为next,这个next就是我们今天的主角,next函数主要负责将控制权交给下一个中间件。如果当前中间件没有终结请求,并且next没有被调用,那么请求将被挂起,后边定义的中间件将得不到被执行的机会。
     
    类比到django中来说:就是我们定义了很多个中间件,比如A,B,C。
    如果我们在A中实现了一些功能,这是和,我们在A的回调函数内应该这么写
    app.all('/', function(req, res, next) {
        // 在这里完成了一些功能。
        next();
    });
    如果没有在B中没有写next,也就是没有写next()。而且没有直接retrun。那么,请求将会被挂起。
     
     
    2.何时使用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: {}
      });
    });
     
    发送请求"/a",控制台打印日志如下:
     
    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)
    

      

    为什么代码会抛异常呢,就是因为我们在res.send之后调用了next函数,虽然我们本次的请求已经被终止,但后边的404中间件依旧会被执行,而后边的中间件试图去向res的headers中添加属性值,所以就会抛出上边的异常。
     
    读到这你可能会有个疑问,如果我不在res.send后边调用next函数,那后边定义的404中间件是不是永远都不会被执行到。现在我们删除res.send后边next函数调用,发送请求"/xxx",我们就会发现404中间件被执行了,(ㄒoㄒ),这不是和我们之前说的矛盾了吗,我们的自定义中间件没有调用next,但后边定义的中间件仍旧被执行了,这究竟是为什么呢。看来只能求助源码了~~~
     
     
    3.Next的内部机制
     
    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);
        }
      }
    

      

    上边就是express中next的源码,为了更容易说明问题,对代码进行了删减。从上边的源码可以发现,next函数内部有个while循环,每次循环都会从stack中拿出一个layer,这个layer中包含了路由和中间件信息,然后就会用layer和请求的path就行匹配,如果匹配成功就会执行layer.handle_request,调用中间件函数。但如果匹配失败,就会循环下一个layer(即中间件)。
     
    现在我们就能解释上边提出的问题了,为什么我们的自定义中间件中没调用next函数,但后边的404中间件仍旧会被执行到,因为我们请求的"/xxx"匹配不到我们注册的"/a"路由中间件,所以while循环会继续往下执行,匹配404中间件成功,所以会执行404中间件。
     
    注意:
    app.use注册的中间件,如果path参数为空,则默认为"/",而path为"/"的中间件默认匹配所有的请求
     
     
     
     
     
  • 相关阅读:
    Zookeeper 笔记
    个人学习笔记
    VS Window窗体 (C#)程序 连接sql server 数据库
    每周总结 11.9~11.15
    需求分析 第七稿 功能实现进度09
    数据简单清洗和图标联动展示
    IDEA创建文件自动添加作者名及时间
    springcloudalibaba中文文档
    ContractHolder.parseAndValidateMetadata(Ljava/lang/Class;)Ljava/util/List;
    Sentinel fallback失效
  • 原文地址:https://www.cnblogs.com/haiguixiansheng/p/10718761.html
Copyright © 2011-2022 走看看