以下是我的代码的相关部分,为简化问题而简化:
app.use(middleware1);
app.use(middleware2);
function middleware1(req,res,next) {
...//get extension of request URL
switch (extension)
{
case 'js' :
..
case 'html': res.sendFile(res.originalUrl,function(err) {});
break; //break1
case 'njm' : break; //break2
default : console.log('default');
break;
}
}
function middleware2(req,res,next) {
console.log("I am in middleware2");
}
问题是这样的:例如,如果扩展名是html,我不会期望中间件2被调用,但确实如此! 似乎sendFile启动文件的发送,控制执行在调用sendFile的回调之前就已经过了。如果我将next1替换为next()或者返回next()同样存在缺陷 - 在执行sendFile的回调之前,Control将转到下一个middleware2。如何阻止中间件2被调用第一组扩展?此外,如果扩展名为“njm'”,即使没有next(),也会调用middleware2。为什么呢?
请不要建议使用Express静态中间件,因为我有一些逻辑涉及提供不同的文件类型,这比上面给出的简化方案更复杂。
答案 0 :(得分:2)
res.sendFile()
有点独特。如果您未通过完成回调,则会为您拨打next()
。请参阅本答复后面的详细信息。
您所报告的内容与Express表示它的工作方式相反,所以我认为必须有一些事情不会像您报告的那样发生。
Express中间件的重点在于,任何给定的中间件调用都有机会对请求进行字段处理,然后通过生成响应来处理请求,或者如果它希望中间件链继续,则调用{{1 }}。如果未调用next()
,则中间件链将停止,并且在当前中间件链中不会调用任何其他内容。如果这是应用程序级中间件(使用next()
),那么如果您不从中间件调用app.use()
,则不应再进行应用程序级中间件处理。
如果当前的中间件没有结束请求 - 响应周期,那么 必须调用next()将控制权传递给下一个中间件,否则就是 请求将被搁置。
这篇关于Express中间件的文章非常好:Express Middleware Demystified有助于解释更多细节。它还确认,如果您不打电话给next()
,那么将不再在中间件链中调用处理程序。
next()
有一个特例。如果您未通过完成回调,则会自行调用res.sendFile()
。如果您将完成回调传递给它,那么它将不会调用next()
。这似乎没有详细记录,但如果您查看next()
代码here,就可以看到它是如何工作的。
有一点需要注意调试,有时候浏览器会发出比你想象的更多的请求。例如,当您第一次访问某个站点的主页时,浏览器可能会要求提供网站图标,这会导致额外的请求到达您的Web服务器。所以,我想知道你的res.sendFile()
调试是否让你感到困惑,因为可能有多个请求进入,而不是一个请求通过两个中间件。此外,交叉源Ajax调用也可以在请求实际的Ajax调用之前请求AJAX选项。
您可以区分这样的多个请求,并在同一请求中更准确地查看它是否实际上从console.log()
转到middleware1
:
middleware2
此外,似乎var reqCntr = 1;
app.use(middleware1);
app.use(middleware2);
function middleware1(req,res,next) {
if (!req.reqCntr) {
req.reqCntr = reqCntr++;
}
console.log("middleware1: " + req.reqCntr);
...//get extension of request URL
switch (extension)
{
case 'js' :
..
case 'html': res.sendFile(res.originalUrl,function(err) {});
// return here because the request is now handled
return;
case 'njm' : break; //break2
default : console.log('default');
break;
}
// the request was not handled so call the next link in the middleware chain
next();
}
function middleware2(req,res,next) {
if (!req.reqCntr) {
req.reqCntr = reqCntr++;
}
console.log("middleware2: " + req.reqCntr);
}
您未处理请求的情况应致电middleware1
,因此我已修改上述next()
来执行此操作。如果您在switch语句中处理请求,则middleware1
。如果没有,则会调用return
。
答案 1 :(得分:1)
一旦您编写app.use(middleware2)
,middleware2
将在中间件1完全执行后用于app
上的所有路由。
由于您想有条件地使用middleware2,我建议您使用以下方法:
app.use(middleware1);
function middleware1(req,res,next) {
...//get extension of request URL
switch (extension)
{
case 'js' : middleware2(req, res, next);
break;
case 'html': res.sendFile(res.originalUrl,function(err) {});
break;
case 'njm' : middleware2(req, res, next);
break;
default : middleware2(req, res, next);
break;
}
}
function middleware2(req,res,next) {
console.log("I am in middleware2");
}