Express / Connect:调用redis后无法解析正文

时间:2013-05-10 22:05:36

标签: express connect middleware

我试图通过仅根据请求的路径调用某些中间件函数来缩短我的Express / Connect中间件管道。

但是,以下内容将失败:

_cookieParser(req, res, function(err) {
     if(err) return next(err);
     _session(req, res, function(err) {
         if(err) return next(err);
         _csrf(req, res, function(err) {
              if(err) return next(err);
              loadUserFromSession(req, res, function(err) {
                   if(err) return next(err);
                   if(req.method == "POST") {
                       _bodyParser(req, res, next);
                   } else {
                       next();
                   }
              });
          });
     });
});

但这样可以正常工作:

_cookieParser(req, res, function(err) {
     if(err) return next(err);
     _session(req, res, function(err) {
         if(err) return next(err);
         _csrf(req, res, function(err) {
              if(err) return next(err);
              _bodyParser(req, res, function(err) {
                   if(err) return next(err);
                   loadUserFromSession(req, res, next);
              });
          });
     });
});

loadUserFromSession位于:

function loadUserFromSession(req, res, next) {
    if(req.session && req.session.userId) {
        userFunctions.getUserById(req.session.userId, function(err, user) {
            if(err) return next(err);
            if(user) {
                req.user = user;
                return next();
            } else {
                req.session.destroy();
                return next(new Error('Unauthenticated'));
            }
        });
    } else {
        return next(new Error('Unauthenticated'));
    }        
};

为什么我不能在loadUserFromSession()之后调用bodyParser()?

修改

对于失败/意外结果缺乏细节感到抱歉。

如果我在loadUserFromSession()之后放入bodyParser()或只是json()(因为POST内容是json),则调用永远不会返回到json()内部。如果我在节点检查器中的res.on('data')或res.on('end')上放置断点,则不会被触发。

json中间件的来源如下:

exports = module.exports = function(options){
  var options = options || {}
    , strict = options.strict !== false;

  var limit = options.limit
    ? _limit(options.limit)
    : noop;

  return function json(req, res, next) {
    if (req._body) return next();
    req.body = req.body || {};

    if (!utils.hasBody(req)) return next();

    // check Content-Type
    if ('application/json' != utils.mime(req)) return next();

    // flag as parsed
    req._body = true;

    // parse
    limit(req, res, function(err){
      if (err) return next(err);
      var buf = '';
      req.setEncoding('utf8');
      req.on('data', function(chunk){ 
        buf += chunk                  <==BREAKPOINT NEVER GETS CALLED
      });
      req.on('end', function(){
        var first = buf.trim()[0];    <==BREAKPOINT NEVER GETS CALLED

        if (0 == buf.length) {
          return next(400, 'invalid json, empty body');
        }

        if (strict && '{' != first && '[' != first) return next(400, 'invalid json');
        try {
          req.body = JSON.parse(buf, options.reviver);
          next();
        } catch (err){
          err.body = buf;
          err.status = 400;
          next(err);
        }
      });
    });
  }
};

1 个答案:

答案 0 :(得分:0)

好的,请考虑这个建议/代码审查而不是具体的答案,但希望这会有所帮助。

首先,我的猜测是理解以下内容将解决您的问题并使您失望,尽管我不能确切地说出为什么您的上述第二个示例与给定您的隔离片段的第一个示例的行为不同,但是根据此信息进行一些实验:对于给定的请求,一系列事件(dataend等)将只触发一次。如果侦听器在发射时没有连接,则该侦听器永远不会被调用。如果一个听众在他们开火后被附加,它将永远不会被召唤。 bodyParser有代码可以避免尝试多次重新解析同一个请求主体(因为必要的事件永远不会触发,代码会挂起而不响应请求)。

所以,我怀疑你的应用程序中有app.use(express.bodyParser()),并且在上面的自定义内容之前,中间件正在调用并运行。因此,我的建议也解决了您的文件上传安全问题:

请不要像示例中那样全局安装bodyParserapp.use(express.bodyParser())。此代码适用于第1天的示例应用程序,但它对于生产站点来说完全不合适。你应该做一些像:

app.post('/upload/some/file', express.bodyParser(), myUploadHandler);

只需将身体解析器准确地用于需要的地方,而不是其他地方。不要再深入了解一堆奇异的中间件。通过内置于连接中的中间件堆栈设计,可以通过干净的方式获得在HARMONY中工作所需的功能,安全性和效率。一般来说,了解您可以在不同的路径上使用不同的中间件堆栈,并且可以配置express / connect以便在逐个路径的基础上很好地匹配您想要发生的事情。