2017-06-06 55 views
1

我想創建一個簡單的express express中間件過濾器,它應該查看POST正文並確定它是否應該通過管道連接到正確的服務器或阻止。如果我使用body-parser,看起來確實可以得到req.body,但是當我將請求傳送到另一個外部服務器時,它會從請求中消失。在請求之前阻止快速的身體分析器去除身體.pipe

我試圖解決這一問題的方法是:

//Router 
router.route('') 
    .post(authController.isAuthenticated, 
     urlHelper.bodyParser,    //Without these two, everything pipes correctly 
     urlHelper.filterBasedOnSomething, //Without these two, everything pipes correctly 
     urlHelper.pipeToTrustedZone); 

在urlHelper:

const filterBasedOnSomething = function (req, res, next) { 
     if (req.body 
      && req.body.something === 'some string' 
      && req.body.somethingElse === 'some other value') { 
      return res.status(403).send("You shall not pass"); 
     } else { 
      next(); 
     } 
    } 
const pipeToTrustedZone = function (req, res) { 
     //Here we are figuring out the correct forwarding url. This is simplified a little for the question, but it is well tested and works. 
     var url = getProxiedPath(req.baseUrl) + req.originalUrl; 
     req.pipe(request({ qs: req.query, uri: url }).on('error', function (err) { 
      log.info(err); 
      return res.sendStatus(400); 
     })) 
      .pipe(res); 

}; 
module.exports = { 
    bodyParser: require('body-parser').json(), 
    filterBasedOnSomething: filterBasedOnSomething, 
    pipeToTrustedZone: pipeToTrustedZone, 
    //.. 
} 

這似乎給了我在我的過濾方法req.body,但身體消耗並且在管道向前未收到。我嘗試了多種東西,例如req.emit('data', JSON.stringify(req.body));req.write(..,但它似乎都失敗了。

有沒有辦法讓我在查看請求主體之前進一步管道而不刪除它?或者我的方法存在繼承問題?

我發現多個GitHub的問題等等有關這個問題,但我還沒有成功地獲得任何這些方法的工作:

https://github.com/expressjs/body-parser/issues/74

Writing express middleware to get raw request body before body-parser

https://github.com/expressjs/body-parser/issues/94

回答

1

Is there a way for me to look at the request body before piping it further without deleting it? Or is there an inherit problem with my approach?

固有的問題是,你想先讀PI流盡管流已經被閱讀,但它已經消失了。

你需要做的是要麼緩存流,同時它是隻讀,以便它可以在稍後管道或從身體解析器的輸出重建身體。

但是你不能倒回一個流並重新開始閱讀它,因爲這意味着記錄所有的流事件在內存中,而使用流的常見優點是你不需要記錄內存中的所有內容,一次處理一個data事件。

如果您是否想要管道流的決定可以基於身體外部的數據 - 如路徑或某些標頭等 - 則可以僅爲這些情況使用身體分析器中間件沒有管道。

但是,如果決定是基於對身體的實際內容是你的榜樣的話,那麼你別無選擇,只能先讀它 - 這點不能再次讀取處。

有幾個模塊,可以幫你:

,但你可能會從身體解析器解析輸出重建身體更好類似於:

request({ qs: req.query, uri: url, body: req.body, json: true }) 

an d只管道響應。

+0

我明白了。你知道我該如何記錄數據並在以後重新發送?我嘗試了'req.emit('data',bodyData);'有和沒有'req.emit('end');'。我試了一大堆東西。也許有一種方法可以重新創建'req'變量並進一步移植? – Automatico

+1

@ Cort3z如果你不需要管道完全相同的流,但只是相同的數據,那麼你可能能夠將你的身體添加到請求。查看更新後的答案。 – rsp

+0

我收到'{「message」:「write after end」,「name」:「Error」,「stack」:「錯誤:在ClientRequest.write(_http_outgoing.js:485:15) n'設置'body:req.body'時是否需要成爲字符串化的json? – Automatico