A bit of internals here. The main purpose of express app handle function is to send a response to the client, and terminate the request-response cycle. And termination of this cycle can be done by one of the response methods (e.g. res.end(), res.json(), etc). Meaning if a middleware or route handler does some actions but then doesn't call one of the response methods or pass the control to the next handler or middleware, the request-response cycle will not be terminated. But what the next does depends on where and how it gets called.
为了管理不同的任务(路由处理程序、中间件),express创建了堆栈。它们看起来像一个任务队列。每个路由器和路由创建自己的任务堆栈;
express应用程序的使用方法将任务(中间件功能)推到路由器的堆栈中。app.get、app.post等在路由器中创建了一个单独的路由(有自己的堆栈,并将路由的实际处理程序推给它),然后将这些路由处理程序包在一个函数中推给路由器。这意味着当路由在路由器堆栈中创建时,就像推送子任务的路由任务(包装器函数)。
// 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');
});
由于路由有自己的堆栈,调用不带参数的next只会让我们得到路由的下一个处理程序:
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');
}
);
在中间件内部调用next (express建议应用use方法挂载中间件)会让我们到达路由器的下一个路由或中间件,导致中间件(挂载时)被推入路由器堆栈。
Next接受不同的参数。任何不是“route”或“router”的参数都将被视为错误,并将被传递给错误中间件,该中间件必须在所有路由之后挂载,并且有四个参数:
// error handling middleware
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.send(error.message || 'Server internal error');
});
字符串'route'作为next的参数将跳过所有剩余的路由处理程序,并为我们提供路由器的下一个路由:
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');
}
);
String 'router'作为next的参数可以让我们脱离当前路由器:
// 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');
}
);