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為"/"的中間件默認匹配所有的請求
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM