快递下一个功能,它真正适用于什么?

时间:2012-10-30 05:18:39

标签: node.js express

一直试图找到next()方法的优点。在Express文档中,它表示可以使用next('route')跳转到该路由并跳过其间的所有路由,但有时会调用next而不带参数。有人知道描述next函数的好教程等吗?

9 个答案:

答案 0 :(得分:133)

没有参数的

next()说“开玩笑,我实际上并不想处理这个”。它会重新进入并尝试找到匹配的下一条路线。

这很有用,比如你想要一些带有url slugs的页面管理器,还有很多其他东西,但这里有一个例子。

app.get('/:pageslug', function(req, res, next){
  var page = db.findPage(req.params.pageslug);
  if (page) {
    res.send(page.body);
  } else {
    next();
  }
});

app.get('/other_routes', function() {
  //...
});

组成代码应检查数据库中是否存在具有特定id slug的页面。如果它找到一个渲染它!如果找不到,则忽略此路由处理程序并检查其他处理程序。

所以没有参数的next()允许假装你没有处理路线,所以别的东西可以代替它。


app.all('*')的点击计数器。这允许您执行一些共享设置代码,然后转到其他路由以执行更具体的操作。

app.all('*', function(req, res, next){
  myHitCounter.count += 1;
  next();
});

app.get('/other_routes', function() {
  //...
});

答案 1 :(得分:114)

在大多数框架中,您都会收到请求并希望返回响应。由于Node.js的异步特性,如果你正在做非平凡的事情,你会遇到嵌套回调的问题。为了防止这种情况发生,Connect.js(在v4.0之前,Express.js是connect.js之上的一个层)有一些叫做中间件的东西,它是一个带有2,3或4个参数的函数。

function (<err>, req, res, next) {}

您的Express.js应用程序是这些功能的堆栈。

enter image description here

路由器很特殊,它的中间件可以让你为某个网址执行一个或多个中间件。所以它是堆栈中的堆栈。

接下来做什么呢?很简单,它告诉您的应用程序运行下一个中间件。但是当你把东西传给下一个时会发生什么? Express将中止当前堆栈并运行具有4个参数的所有中间件。

function (err, req, res, next) {}

此中间件用于处理任何错误。我喜欢这样做:

next({ type: 'database', error: 'datacenter blew up' });

有了这个错误,我可能会告诉用户出错的地方并记录真正的错误。

function (err, req, res, next) {
   if (err.type === 'database') {
     res.send('Something went wrong user');
     console.log(err.error);
   }
};

如果您将Express.js应用程序描绘成一个堆栈,您可能会自己修复很多怪异问题。例如,当您在路由器之后添加Cookie中间件时,您的路由将不会有cookie。

答案 2 :(得分:46)

恕我直言,这个问题的接受答案并不准确。正如其他人所说,它实际上是关于控制链中的下一个处理程序何时运行。但是我想提供更多的代码来使它更具体。假设你有这个简单的快递应用程序:

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

app.get('/user/:id', function (req, res, next) {
    console.log('before request handler');
    next();
});

app.get('/user/:id', function (req, res, next) {
    console.log('handling request');
    res.sendStatus(200);
    next();
});

app.get('/user/:id', function (req, res, next) {
    console.log('after request handler');
    next();
});

app.listen(3000, function () {
    console.log('Example app listening on port 3000!')
});

如果你这样做

curl http://localhost:3000/user/123

你会看到这个打印到控制台:

before request handler
handling request
after request handler

现在,如果您在中间处理程序中注释掉对next()的调用,请执行以下操作:

app.get('/user/:id', function (req, res, next) {
    console.log('handling request');
    res.sendStatus(200);
    //next();
});

您将在控制台上看到这一点:

before request handler
handling request

请注意,最后一个处理程序(打印after request handler的处理程序)不会运行。那是因为你不再告诉express来运行下一个处理程序。

因此,如果你的&#34;主要&#34;那么这并不重要。 handler(返回200的那个)成功与否,如果你想让其余的中间件运行,你必须调用next()

什么时候派上用场?假设您要记录所有进入某个数据库的请求,无论请求是否成功。

app.get('/user/:id', function (req, res, next) {
    try {
       // ...
    }
    catch (ex) {
       // ...
    }
    finally {
       // go to the next handler regardless of what happened in this one
       next();
    }
});

app.get('/user/:id', function (req, res, next) {
    logToDatabase(req);
    next();
});

如果要运行第二个处理程序,则必须在第一个处理程序中调用next()

请记住,节点是异步的,因此无法知道第一个处理程序的回调何时完成。你必须通过致电next()告诉它。

答案 3 :(得分:7)

next()without parameter调用框架中的下一个路由处理程序或下一个中间件。

答案 4 :(得分:1)

在一个地方总结正确提到的答案,

  • next() :将控制移到同一路径中的下一个函数。的情况 单一路线中的​​多种功能。
  • next('route') : 跳过所有剩余的路线,将控制权移至下一条路线 当前路径中的函数。
  • next(err) : 将控制权移至错误中间件
app.get('/testroute/:id', function (req, res, next) {
  if (req.params.id === '0') next() // Take me to the next function in current route
  else if (req.params.id === '1') next('route') //Take me to next routes/middleware by skipping all other functions in current router  
  else next(new Error('Take me directly to error handler middleware by skipping all other routers/middlewares'))
}, function (req, res, next) {
  // render a regular page
  console.log('Next function in current route')
  res.status(200).send('Next function in current route');
})

// handler for the /testroute/:id path, which renders a special page
app.get('/testroute/:id', function (req, res, next) {
  console.log('Next routes/middleware by skipping all other functions in current router')
  res.status(200).send('Next routes/middleware by skipping all other functions in current router');
}) 
//error middleware
app.use(function (err, req, res, next) {
  console.log('take me to next routes/middleware by skipping all other functions in current router')
  res.status(err.status || 500).send(err.message);
});

答案 5 :(得分:0)

问题还询问了next('route')的使用,到目前为止,似乎已经提供了答案:

  1. next()的用法:

简而言之:下一个中间件功能。

从此官方Express JS documentation - 'writing-middleware' page中摘录:

“中间件函数myLogger仅打印一条消息,然后通过调用next()函数将请求传递给堆栈中的下一个中间件函数。”

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

app.use(myLogger)

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)

This page of Express JS documentation指出:“如果当前中间件函数未结束请求-响应周期,则必须调用next()将控制权传递给下一个中间件函数。否则,请求将被挂起。” < / p>

  1. next('route')的用法:

简而言之:下一路径(与nextstrong的下一中间件功能相比)

从此 Express JS documentation - 'using-middleware' page中提取:

“要从路由器中间件堆栈中跳过其余中间件功能,请调用next('route')将控制权传递给下一条路由。注意:next('route')将起作用仅在使用app.METHOD()或router.METHOD()函数加载的中间件函数中。

此示例显示了一个中间件子堆栈,该子堆栈处理到/ user /:id路径的GET请求。”

app.get('/user/:id', function (req, res, next) {
  // if the user ID is 0, skip to the next route
  if (req.params.id === '0') next('route')
  // otherwise pass the control to the next middleware function in this stack
  else next()
}, function (req, res, next) {
  // render a regular page
  res.render('regular')
})

// handler for the /user/:id path, which renders a special page
app.get('/user/:id', function (req, res, next) {
  res.render('special')
})

答案 6 :(得分:0)

这只是意味着将控制权传递给下一个处理程序。

欢呼

答案 7 :(得分:0)

请注意next()上方的调用。调用此函数将调用应用程序中的下一个中间件函数。 next()函数不是Node.js或Express API的一部分,而是传递给中间件函数的第三个参数。 next()函数可以命名为任何名称,但按照约定,它始终命名为“ next”。为避免混淆,请始终使用此约定。

答案 8 :(得分:0)

next() 是带有req的中间件函数的回调参数,res是以下代码中next的http请求和响应参数。

app.get('/',(req,res,next)=> {next()});

因此next()调用传入的中间件函数。如果当前的中间件功能没有结束请求-响应周期,则应调用next(),否则请求将被挂起并超时。

当将多个中间件功能传递给 app.use 或app.METHOD时,需要在每个中间件功能中调用

next() ,否则将不会调用下一个中间件功能(如果传递了多个中间件功能)。要跳过对其余中间件功能的调用,请在中间件功能内调用 next('route') ,此后不应再调用其他中间件功能。在下面的代码中,将调用fn1并且还将调用fn2,因为next()在fn1中被调用。但是,由于在fn2中调用了next(“ route”),因此不会调用fn3。

app.get('/fetch', function fn1(req, res, next)  {
console.log("First middleware function called"); 
    next();
}, 
function fn2(req, res, next) {
    console.log("Second middleware function called"); 
    next("route");
}, 
function fn3(req, res, next) {
    console.log("Third middleware function will not be called"); 
    next();
})