首頁  >  文章  >  web前端  >  nodejs操作express中的next

nodejs操作express中的next

php中世界最好的语言
php中世界最好的语言原創
2018-04-18 11:20:291899瀏覽

這次帶給大家nodejs操作express中的next,nodejs操作express中next的注意事項有哪些,下面就是實戰案例,一起來看一下。

相信很多人對於nodejs對express中next不是很了解,大多數人不知道其中的next有什麼作用,在什麼情況下使用,今天文章中就給大家詳細介紹下其使用方法,感興趣的一起來了解下。

最近公司在使用node做前後端分離,採用的web框架是express,所以對express框架進行了深入的了解,前段時間寫了篇關於express路由的文章,但是在那篇文章中貌似少了一個很重要的內容,就是express的next,所以今天單獨來談談express的next。

關於next主要從三點來進行說明:

  • # next的作用是什麼?

  • 我們應該在何時使用next?

  • next的內部實作機制是什麼?

Next的作用

我們在定義express中間件函數的時候都會將第三個參數定義為next,這個next就是我們今天的主角,next函數主要負責將控制權交給下一個中間件,如果當前中間件沒有終結請求,且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: {}
 });
});

發送請求"/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,但後邊定義的中間件仍舊被執行了,這究竟是為什麼呢。看來只能求助原始碼了~~~

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為"/"的中間件則預設符合所有的請求。

有一點需要特別指出,其實我們在定義路由中間件的時候函數的第三個參數next和我們定義非路由中間件的函數的第三個參數next不是同一個next,我們在上邊看到的是非路由中間件的next,而路由中間件的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);
  }
 }

这个next比上边的那个next要简单很多,它负责同一个路由的多个中间件的控制权的传递,并且它会接收一个参数"route",如果调用next(“route”),则会跳过当前路由的其它中间件,直接将控制权交给下一个路由。

最后有必要再说一说next(err),next(err)是如何将控制权传递到错误处理中间件的,从前边的代码我们知道,当调用next(err)是,express内部会调用layer.handle_error,那我们来看看它的源码

Layer.prototype.handle_error = function handle_error(error, req, res, next) {
 var fn = this.handle;
 if (fn.length !== 4) {
  // not a standard error handler
  return next(error);
 }
 try {
  fn(error, req, res, next);
 } catch (err) {
  next(err);
 }
};

代码中的fn就是中间件函数,express会对fn的参数个数进行判断,如果参数个数不等于4则认为不是错误处理中间件,则继续调用next(err),这样就会进入到下一个中间件函数,继续进行参数个数判断,如此方式一直到某个中间件函数的参数个数是4,就认为找到了错误处理中间件,然后执行此中间件函数。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

Express Session实现登录验证功能(附代码)

js面向对象深入理解

以上是nodejs操作express中的next的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn