本文介绍了与Express Middleware中的控制流有关的SendFile问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我代码的相关部分,为缩小问题范围而进行了简化:

Here is relevant portion of my code, simplified for narrowing the issue:

 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,则我根本不希望调用Middleware2,但确实会调用它!似乎sendFile启动了文件的发送,并且在执行sendFile的回调之前,控制执行一直在进行.如果我用next()代替break1或返回next(),那将同样存在缺陷-控制将在执行sendFile的回调之前转到下一个Middleware2.如何阻止Middleware2调用第一组扩展?另外,如果扩展名是'njm',即使没有next(),也会调用middleware2.为什么?

Question is this: In case extension is html, for example, I would not expect middleware2 to be called at all but it does!It appears that sendFile initiates the sending of the file and control execution falls thru before the sendFile's callback is called. If I replace break1 by next() or return next() that would be equally flawed - Control will go to next middleware2 before sendFile's callback is executed. How do I stop middleware2 from getting called for the first set of extensions? Also, if extension is 'njm', even without a next(), middleware2 is called. Why?

请不要建议使用Express静态中间件,因为在处理不同的文件类型时涉及一些逻辑,这比上面给出的简化方案要复杂得多.

Please do not suggest using Express static middleware because I have some logic involved in serving different file types which is more complex then the simplified scenario given above.

推荐答案

res.sendFile()有点独特.如果不传递完成回调,则它将为您调用next().稍后在此答案中查看详细信息.

res.sendFile() is a bit unique. If you don't pass it a completion callback, then it will call next() for you. See details later in this answer.

您要报告的内容与Express所说的相反,因此我认为您报告的方式肯定没有完全发生.

What you are reporting is opposite of how Express says it works so I think there must be something that is not quite happening the way you report it.

Express中间件的全部要点是,任何给定的中间件调用都有机会提出请求,然后要么通过生成响应来处理请求,要么如果它希望中间件链继续,则调用next() .如果未调用next(),则中间件链停止,并且在当前中间件链中未调用其他任何东西.如果这是应用程序级中间件(带有app.use()),那么如果您不从中间件中调用next(),则不应进行进一步的应用程序级中间件处理.

The whole point of the Express middleware is that any given middleware call gets a chance to field the request and then it either handles the request by generating a response or if it wants the middleware chain to continue, then it calls next(). If next() is not called, then the middleware chain stops and nothing else is called in the current middleware chain. If this is application level middleware (with app.use()), then there should be no further app level middleware processing if you do not call next() from your middleware.

这是来自快速中间件页面的报价:

这是一篇有关Express中间件的很好的文章: Express Middleware Demystified ,可帮助解释更多细节.它还确认,如果您不调用next(),那么在中间件链中将不再调用任何处理程序.

This is a pretty good article about Express middleware: Express Middleware Demystified which helps explain a lot more of the details. It also confirms that if you don't call next() then no more handlers will be called in the middleware chain.

res.sendFile()有一种特殊情况.如果不传递完成回调,则它将调用next()本身.如果将完成回调传递给它,则它将不会调用next().这似乎没有很好的文档记录,但是如果您查看res.sendFile()代码此处,您可以看到它的工作原理.

There is one special case with res.sendFile(). If you don't pass it a completion callback, then it will call next() itself. If you pass it the completion callback, then it will not call next(). This does not appear to be well documented, but if you look at the res.sendFile() code here, you can see how it works.

调试时要注意的一件事是,有时浏览器发出的请求比您可能意识到的要多.例如,当您第一次访问站点的主页时,浏览器可能会要求提供网站图标,这会导致额外的请求访问您的Web服务器.因此,我想知道您的console.log()调试是否会使您感到困惑,因为可能有多个请求传入,而不是同时通过两个中间件的单个请求.另外,跨源Ajax调用也可能在请求实际Ajax调用之前先请求AJAX选项.

One thing to watch out for with your debugging is that sometimes the browser issues more requests than you may realize. For example, when you first hit a homepage of a site, the browser may ask for the website favicon which causes an extra request to hit your web server. So, I'm wondering if your console.log() debugging is confusing you because perhaps there is more than one request coming in, not a single request that is going through both pieces of middleware. Also, a cross origin Ajax call may request AJAX options before requesting the actual Ajax call too.

您可以像这样区分多个请求,并更准确地查看同一请求是否实际上是从middleware1middleware2:

You can differentiate multiple requests like this and more accurately see whether it is actually going from middleware1 to middleware2 on the same request:

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(),因此我对上述middleware1进行了修改.如果您在switch语句中处理请求,则return.如果没有,它将进入对next()的调用.

Also, it seems like the middleware1 cases where you are not handling the request should call next() so I've modified the above middleware1 to do that. If you handle the request in the switch statement, then return. If not, it will fall through to a call to next().

这篇关于与Express Middleware中的控制流有关的SendFile问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-02 07:22