防止快速正文解析器在 request.pipe 之前删除正文

Prevent express body-parser from removing body prior to request.pipe

我正在尝试创建一个简单的快速中间件过滤器,它应该查看 POST 主体并确定它是否应该通过管道传输到正确的服务器,或者被阻止。如果我使用 body-parser 似乎我确实获得了可用的 req.body,但是当我将请求通过管道传输到另一个外部服务器时它从请求中消失了。

我尝试解决这个问题的方法如下:

//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 问题和与此相关的 SO 问题,但我没有成功地使这些方法中的任何一种起作用。:

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

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?

固有的问题是您希望先读取流然后通过管道传输它 - 即使流已经被读取并且已经消失。

您需要做的是在读取流时缓存流以便稍后可以通过管道传输,或者从 body-parser.[=15= 的输出重建 body ]

但是你不能倒回流并再次开始读取它,因为这意味着将所有流事件记录在内存中并且使用流的通常优点是你不需要将所有内容都记录在内存中,你一次只处理一个 data 事件。

如果可以根据 body 之外的数据来决定是否要通过管道传输流 - 例如路径或某些 headers 等 - 那么您可以使用body-parser 中间件仅适用于未通过管道传输的情况。

但是,如果决定是基于 body 的实际内容(如您的示例中的情况),那么您别无选择,只能先阅读它 - 此时无法再次阅读。

很少有模块可以帮助您:

但是你可能会更好地从 body-parser 的解析输出中重建 body 像这样的东西:

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

并且仅通过管道传递响应。