表达下一个功能,它的真正作用是什么?


124

一直在试图找到一种很好的next()方法描述。在Express文档中,它说next('route')可用于跳转到该路由并跳过其间的所有路由,但有时next被称为没有参数。有人知道描述该next功能的优秀教程等吗?

Answers:


159

next()毫无争议的说法是“开玩笑,我实际上并不想处理这个问题”。它返回并尝试查找将匹配的下一条路线。

这很有用,例如,如果您想使用某种带有URL插件的页面管理器以及许多其他功能,但这是一个示例。

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标记的页面。如果找到一个渲染器!如果找不到,则忽略此路由处理程序并检查其他路由处理程序。

因此next(),没有参数就可以假装您没有处理该路线,以便其他人可以选择它。


或点击app.all('*')。这使您可以执行一些共享的设置代码,然后转到其他路线以执行更具体的操作。

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

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

好答案!我也看到了next的其他用法,例如next(err)和next('route')。您现在的目的是什么?何时要传播错误,何时要跳转到特定路线?
安德烈亚斯·塞伦沃尔

8
@AndreasSelenwall next('route')特定于@,app.VERB()并且在路由具有多个回调以“ 绕过其余路由回调 ”时next(err)使用。@用于跳转到任何“ 错误中间件 ”(E从帖子中)。
乔纳森·洛诺夫斯基

5
已投票。只是为了这句话:“开个玩笑,我实际上不想要处理这个问题”,这使我明白我在寻找什么。我看到了许多类似的问题,并在一句话中找到了解决方案。
Pedro Barros

8
next()不带参数的调用并不能真正告诉系统“我不想处理”,它只是告诉系统完成此操作后继续处理任何剩余的中间件。调用不是错误条件next(),它是正常流程的一部分。如果您不拨打电话,next()将不会处理其他任何路由。
d512

1
我希望这个网站上的更多答案是为外行写的...'next(),不带任何参数,表示“只是在开玩笑,我实际上不想处理这个问题”。-非常适合菜鸟...(@ d512更好的解释)
daCoda

129

在大多数框架中,您都会收到一个请求,并且想要返回一个响应。由于Node.js的异步特性,如果您做的是琐碎的事情,则会遇到嵌套回调的问题。为了避免这种情况的发生,Connect.js(v4.0之前的Express.js是connect.js之上的一层)具有称为中间件的功能,该中间件具有2、3或4个参数。

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

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

在此处输入图片说明

路由器很特殊,它是一种中间件,可让您针对某个URL执行一个或多个中间件。所以它是一个堆栈中的一个堆栈。

那么接下来该怎么办?很简单,它告诉您的应用程序运行下一个中间件。但是,当您将某些内容传递给下一个内容时会发生什么?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是有意义的。


3
您将在哪里存储此匿名日志记录功能?
dennismonsewicz 2014年

“ Express将中止当前堆栈,并将运行具有4个参数的所有中间件。” 我想知道Express如何运行准确的错误处理程序中间件。谢谢!
Abhishek Agarwal

75

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

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运行下一个处理程序。

因此,您的“主”处理程序(返回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()


Sonfar对我来说是最好的答案。
Norayr Ghukasyan

好解释!

7

不带参数的next()调用框架中的下一个路由处理程序或下一个中间件。


2
还是下一个中间件。
robertklep

1

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

干杯


1

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


0

还询问了有关next('route')的使用的问题,到目前为止,似乎已在提供的答案中涵盖了next('route'):

  1. next()的用法:

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

从此Express JS官方文档中摘录-“写作中间件”页面

“中间件函数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)

Express JS文档的此页面指出:“如果当前中间件函数未结束请求-响应周期,则必须调用next()将控制权传递给下一个中间件函数。否则,请求将被挂起。”

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

简而言之:下一路线(与下一中间件功能)

从此Express JS文档中摘录-“使用中间件”页面

“要从路由器中间件堆栈中跳过其余中间件功能,请调用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')
})

0

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

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

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

当将多个中间件函数传递给app.use或app.METHOD时,需要在每个中间件函数中调用next() fn ,否则将不调用下一个中间件函数(如果传递了多个中间件函数)。要跳过对其余中间件函数的调用,请在中间件函数内调用next('route'),此后不应再调用其他中间件函数。在下面的代码中,将调用fn1并且还将调用fn2,因为在fn1中调用了next()。但是,不会调用fn3,因为在fn2中调用了next('route')。

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();
})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.