参数“next”是什么?用于特快?

假设你有这样一段简单的代码:

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

这个函数有两个参数,reqres,分别表示请求和响应对象。

另一方面,还有其他带有第三个参数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?
}
});

我不明白next()的意义是什么,为什么要使用它。在这个例子中,如果id不存在,next实际上在做什么?

203563 次浏览

它将控制权传递给下一个匹配路由。例如,在你给出的例子中,如果给出了id,你可以在数据库中查找用户,并将其赋值给req.user

下面,你可以有这样的路线:

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

由于/users/123将首先匹配示例中的路由,这将首先检查并找到用户123;那么/users可以对该结果做一些事情。

路线的中间件是一个更灵活和强大的工具,尽管,在我看来,因为它不依赖于特定的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);
});

能够像这样控制流是非常方便的。你可能想让某些页面只对带有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');
});

希望这能给你一些启发!

我也有问题理解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);

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

在理解next之前,你需要对node中的请求-响应周期有一点了解,但不是很详细。 它开始于你对特定资源的HTTP请求,结束于你向用户发送响应,即当你遇到类似res.send(' Hello World ')

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

app.get('/hello', function (req, res, next) {
res.send('USER')
})

这里我们不需要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 !!!!");
});

这里我们有两个中间件函数对应相同的路径。但你总能从第一个人那里得到回应。因为它首先挂载在中间件堆栈中,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 !!!!");
});

next在这里做什么。是的,你可能会有猜测。如果条件为真,它将跳过第一个中间件函数并调用下一个中间件函数,你将得到"Hello Planet !!!!"响应。

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

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

大致如下:-

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


app.get('/hello', function (req, res, next) {
res.send("Hello !!!!");
});
在本例中,需要调用这两个中间件函数。 因此,到达第二个中间件函数的唯一方法是调用next();

如果你不打电话给下一个。不要期望自动调用第二个中间件函数。调用第一个函数后,您的请求将被挂起。第二个函数永远不会被调用,您也不会得到响应。

我还想补充为什么express不调用下一个中间件,并让我们控制它。由于node是异步的,如果express调用下一个中间件而不等待某个异步调用完成,则响应可能不完整或包含错误,因此用户可以控制何时调用下一个中间件函数。

这里有一些内部信息。express app handle函数的主要目的是向客户端发送一个响应,并终止request-response cycle。这个循环的终止可以由response methods中的一个来完成(例如res.end(), res.json()等)。这意味着如果一个中间件或route handler做了一些操作,但随后没有调用其中一个response methods或将控制传递给下一个处理器或中间件,request-response cycle将不会终止。但是next做什么取决于它被调用的位置和方式。

为了管理不同的任务(路由处理程序、中间件),express创建了stacks。它们看起来像tasksqueue。每个routerroute都创建了自己的tasksstack;

express appuse方法将task (middleware函数)推到routerstackapp.getapp.post等在router中创建了一个单独的route(带有自己的stack,并将route的实际express1推入到它),然后将这些route处理程序推入到函数中包装的router。这意味着当在router stack中创建route时,例如route task(包装器函数),并推入app1。

// pushes task to the router stack
app.use((req, res, next) => {
console.log('log request');
next();
});


// creates route, route stack,
// pushes tasks to the route stack,
// wraps tasks in a function (another task)
// pushes wrapper function to the
// router stack
app.get('/', (req, res, next) => {
res.send('Hello World');
});

由于route有自己的stack,调用不带参数的next只会让我们得到route的下一个处理程序:

app.get('/',
(req, res, next) => {
console.log('first handler');
// passes the control to the second handler
next();
},
(req, res, next) => {
console.log('second handler');
res.send('Hello World');
}
);

middleware中调用next (express建议应用use方法来挂载middleware)会使我们到达router的下一个routemiddleware,因为middleware(挂载时)被推到router middleware0。

next接受不同的实参。任何不是'route''router'的参数将被视为错误,并将被传递给error middleware,该参数必须在所有路由之后挂载,并且有四个参数:

// error handling middleware
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.send(error.message || 'Server internal error');
});

字符串'route'作为next的参数将跳过所有剩余的route handlers,并获得router的下一个route:

app.get('/',
(req, res, next) => {
console.log('first handler');
// passes control to the next route
next('route');
},
(req, res, next) => {
// this handler will be skipped
next();
}
);


app.get('/',
(req, res, next) => {
// this route will be called at the end
res.send('Hello World');
}
);

字符串'router'作为next的参数可以使我们脱离当前的router:

// router 'one'
app.get('/',
(req, res, next) => {
console.log('first handler');
// passes control to the next router
next('router');
},
(req, res, next) => {
// this handler will be skipped
next();
}
);


// router 'two'
app.get('/',
(req, res, next) => {
// this route will be called at the end
res.send('Hello World');
}
);