2013-05-10 46 views
1

我試圖通過根據請求的路徑調用某些中間件功能來縮短我的Express/Connect中間件管道。快速/連接:撥打電話給redis後無法解析主體

然而,以下將失敗:

_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')); 
    }   
}; 

我爲什麼不能叫bodyParser() loadUserFromSession()之後?

編輯

對不起,在故障/意想不到的結局缺乏細節。

如果我在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); 
     } 
     }); 
    }); 
    } 
}; 
+0

請修改您的問題,並用實際的錯誤消息和堆棧跟蹤替換「會失敗」,或者如果失敗不是錯誤,請描述錯誤行爲。 – 2013-05-11 23:46:46

+0

方面的評論,使用中間件的方式較少。你有什麼是明確的unidiomatic(禮貌地說)。如果你只想在某些路徑上使用某些東西,那麼嘗試'app.use('/ some/path',someMiddleware)',但是如果不適用於當前請求,那麼大多數中間件的成本確實很小。例如,bodyParser只需檢查請求方法,並在沒有主體的情況下立即調用next()。這是一個你不應該試圖解決的問題。 – 2013-05-11 23:50:34

+0

@PeterLyons在我的問題上增加了更多細節。在結構上,我根本不反對你。我走在這條道路上,不是因爲性能,而是因爲安全。我不希望我的應用上傳每個可能發佈的文件。我有一些公開的端點,有些不是。我不想讓我的應用程序超負荷(或DDOS'd,如果它已知道),只是由人上傳文件到不允許上傳的端點。 – Dave 2013-05-13 15:28:14

回答

0

OK,可以考慮這一建議/代碼審查,而不是一個明確的答案,但希望這有助於。

首先,我的猜測是理解以下內容將解決您的問題並解除您的疑惑,儘管我無法確切地說出爲什麼您的第二個示例的行爲與第一個示例的行爲不同,因爲您的隔離片段的第一個示例不同,信息:對於給定的請求,一系列事件(data,end等)只會觸發一次。如果一個聽衆在他們開槍時沒有連接,那麼這個聽衆就不會被叫到。如果一個聽衆在他們開槍之後被連接,它將永遠不會被召喚。 bodyParser有代碼避免嘗試重新解析同一個請求主體多次(因爲必要的事件永遠不會觸發,代碼會掛起而不響應請求)。因此,我懷疑在你的應用程序中你有app.use(express.bodyParser()),並且中間件在上述自定義事件之前被調用並運行。因此,我的建議,其中也解決您的文件上傳安全問題是:

不要安裝bodyParser全球像你看到的例子:app.use(express.bodyParser())。此代碼適用於第1天的示例應用程序,但對於製作網站來說完全不合適。你應該改爲像這樣:

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

而只是在正確的地方使用body parser而不需要其他地方。不要再往下看你的一堆奇怪的nesty中間件。有一些乾淨的方法可以獲得您在HARMONY中工作所需的功能,安全性和效率,以及內置於連接中的中間件堆棧設計。一般情況下,要明白你可以在不同路徑上使用不同的中間件堆棧,並且可以配置express/connect以便在逐個路徑的基礎上很好地匹配你想要發生的事情。

+0

這是我第一次嘗試;我希望避免在每個路由上都有2/3/4箇中間件調用,特別是如果它們是重複的;因此我的方法如上。 – Dave 2013-05-13 17:31:39