Express中使用的参数"next"是什么?

Men*_*ual 273 node.js express

假设您有一个简单的代码块,如下所示:

app.get('/', function(req, res){
    res.send('Hello World');
});
Run Code Online (Sandbox Code Playgroud)

这个函数有两个参数,req并且res,它们分别代表所述请求和响应对象.

另一方面,还有其他函数,第三个参数被调用next.例如,让我们看看以下代码:

app.get('/users/:id?', function(req, res, next){ // Why do we need next?
    var id = req.params.id;
    if (id) {
        // do something
    } else {
        next(); // What is this doing?
    }
});
Run Code Online (Sandbox Code Playgroud)

我无法理解next()它的用途是什么或为什么被使用.在那个例子中,如果id不存在,那next实际上在做什么?

Ash*_*she 246

它将控制传递给下一个匹配的路径.例如,在给出的示例中,如果给出了用户,则可以在数据库中查找该用户id,并将其分配给req.user.

下面,你可以有一条路线:

app.get('/users', function(req, res) {
  // check for and maybe do something with req.user
});
Run Code Online (Sandbox Code Playgroud)

由于/ users/123将首先匹配您示例中的路由,因此将首先检查并查找用户123; 然后/users可以做一些事情的结果.

路由中间件(注意:链接到2.x文档,但这是在3.x上进行测试)是一个更灵活和强大的工具,但在我看来,因为它不依赖于特定的URI方案或路线订购.我倾向于模拟这样显示的示例,假设Users模型具有异步findOne():

function loadUser(req, res, next) {
  if (req.params.userId) {
    Users.findOne({ id: req.params.userId }, function(err, user) {
      if (err) {
        next(new Error("Couldn't find user: " + err));
        return;
      }

      req.user = user;
      next();
    });
  } else {
    next();
  }
}

// ...

app.get('/user/:userId', loadUser, function(req, res) {
  // do something with req.user
});

app.get('/users/:userId?', loadUser, function(req, res) {
  // if req.user was set, it's because userId was specified (and we found the user).
});

// Pretend there's a "loadItem()" which operates similarly, but with itemId.
app.get('/item/:itemId/addTo/:userId', loadItem, loadUser, function(req, res) {
  req.user.items.append(req.item.name);
});
Run Code Online (Sandbox Code Playgroud)

能够像这样控制流量非常方便.您可能希望某些页面仅对具有admin标志的用户可用:

/**
 * Only allows the page to be accessed if the user is an admin.
 * Requires use of `loadUser` middleware.
 */
function requireAdmin(req, res, next) {
  if (!req.user || !req.user.admin) {
    next(new Error("Permission denied."));
    return;
  }

  next();
}

app.get('/top/secret', loadUser, requireAdmin, function(req, res) {
  res.send('blahblahblah');
});
Run Code Online (Sandbox Code Playgroud)

希望这能给你一些灵感!

  • @John:实际上忽略了返回值; 我只是想回到那里以确保我不会再次调用`next()`.如果我只使用`next(new Error(...)),它会是一样的; 返回;`. (6认同)
  • 为什么有时你会返回next()但有时却没有 (4认同)
  • @level0:忽略返回值;您可以将其视为 `next(new Error(…)); 的简写;返回;`. 如果我们将一个值传递给 `next`,[它被单方面认为是一个错误](https://github.com/expressjs/express/blob/f3d99a4fdbe1531ea609e92c4d4ae6c269d78c7a/lib/router/route.js#L128-129)。我没有过多地研究 express 代码,但是四处挖掘,你会找到你需要的:) (2认同)
  • @level0:(我已将 `return next(...);` 更改为 `next(...); return;`,因此不那么令人困惑。) (2认同)

raj*_*esk 73

我也有问题理解的next(),但这种帮助

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

app.get("/", function(httpRequest, httpResponse, next){
    httpResponse.write("Hello");
    next(); //remove this and see what happens 
});

app.get("/", function(httpRequest, httpResponse, next){
    httpResponse.write(" World !!!");
    httpResponse.end();
});

app.listen(8080);
Run Code Online (Sandbox Code Playgroud)

  • @JohnnyQ这将是自上而下的执行 (14认同)
  • 非常简洁!谢谢!但是你如何确保第一个`.get`被调用而不是第二个? (3认同)
  • @JohnnyQ 谢谢!我只需要有人在我读过的所有文档中简单地说“从上到下执行”。多么简单啊!看起来很明显,但是当你学习这些东西时,没有什么是显而易见的,这真的让我很困扰。 (3认同)

Mav*_*v55 45

在理解之前next,您需要对节点中的请求 - 响应周期有一点了解,但不是很详细.它从您为特定资源发出HTTP请求开始,当您将响应发送回用户时,即当您遇到res.send('Hello World')之类的内容时,它会结束;

让我们来看一个非常简单的例子.

app.get('/hello', function (req, res, next) {
  res.send('USER')
})
Run Code Online (Sandbox Code Playgroud)

这里我们不需要next(),因为resp.send将结束循环并将控制权移交给路由中间件.

现在让我们来看看另一个例子.

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

app.get('/hello', function (req, res, next) {
  res.send("Hello Planet !!!!");
});
Run Code Online (Sandbox Code Playgroud)

这里我们有2个中间件函数用于相同的路径.但你总会从第一个得到回应.因为它首先安装在中间件堆栈中,res.send将结束循环.

但是如果我们总是不想要"Hello World !!!!"回复怎么办呢.在某些情况下,我们可能想要"Hello Planet !!!!" 响应.让我们修改上面的代码,看看会发生什么.

app.get('/hello', function (req, res, next) {
  if(some condition){
    next();
    return;
  }
  res.send("Hello World !!!!");  
});

app.get('/hello', function (req, res, next) {
  res.send("Hello Planet !!!!");
});
Run Code Online (Sandbox Code Playgroud)

这是next做什么的.是的,你可能有gusses.如果条件为真,它将跳过第一个中间件函数并调用下一个中间件函数,您将获得"Hello Planet !!!!"响应.

因此,接下来将控件传递给中间件堆栈中的下一个函数.

如果第一个中间件函数没有发回任何响应但是执行一个逻辑然后从第二个中间件函数得到响应,该怎么办?

如下所示: -

app.get('/hello', function (req, res, next) {
  // Your piece of logic
  next();
});

app.get('/hello', function (req, res, next) {
  res.send("Hello !!!!");
});
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您需要调用两个中间件函数.因此,到达第二个中间件函数的唯一方法是调用next();

如果你不拨打下一个电话怎么办?不要指望第二个中间件函数会自动调用.在调用第一个函数后,您的请求将被挂起.第二个函数永远不会被调用,你不会得到回复.

  • 感谢您通过清晰的示例实际解释了“中间件”是什么,而不仅仅是重复文档。这是唯一一个真正清楚地说明发生了什么、为什么发生以及如何发生的答案。 (3认同)
  • 好吧,看来这是不正确的。我尝试了代码([pastebin here](https://pastebin.com/raw/eTfVZb9j)),然后调用了`next()`之后的代码*。在这种情况下,将“过去next()调用”写入控制台,然后出现“错误:在发送标头后无法设置标头。”错误,因为调用了第二个`res.send`,虽然没有成功。代码流在“ next()”调用之后“返回”,这使得@Ashe的“ returns”(或其他逻辑管理)很重要。 (2认同)
  • @ruffin,是的,你是对的。我们需要在“ next()”之后添加一个return语句,以跳过其余语句的执行。感谢您指出这一点。 (2认同)

小智 8

Next用于将控制传递给下一个中间件函数.如果不是,请求将被挂起或打开.

  • 我不确定这个答案会增加一个近七年的问题...... (3认同)
  • 虽然简短,但这条评论让我想到了这个:https://expressjs.com/en/guide/writing-middleware.html (3认同)
  • @mherzig,它只是一个衬垫,涵盖了所有内容 (2认同)