【问题标题】:Writing express middleware to get raw request body before body-parser在正文解析器之前编写快速中间件以获取原始请求正文
【发布时间】:2016-11-16 17:00:50
【问题描述】:

我编写了一个 Express 中间件来从请求中检索原始正文,并将其设置在 body-parser 中间件之前。

我的自定义中间件正在调用req.setEncoding('utf8'),但这会导致以下正文解析器错误:

错误:不应设置流编码

at readStream (/node_modules/body-parser/node_modules/raw-body/index.js:211:17) 
at getRawBody (/node_modules/body-parser/node_modules/raw-body/index.js:106:12)
at read (/node_modules/body-parser/lib/read.js:76:3)
at jsonParser (/node_modules/body-parser/lib/types/json.js:127:5)

这是我的代码:

var express = require('express');
var bodyParser = require('body-parser')

function myMiddleware() {
  return function(req, res, next) {
    req.rawBody = '';
    req.setEncoding('utf8');

    req.on('data', function(chunk) {
      req.rawBody += chunk;
    });

    req.on('end', function() {
      next();
    });
  }
}

var app = express();
app.use(myMiddleware());
app.use(bodyParser.json());

var listener = app.listen(3000, function() {
});

app.get('/webhook/', function (req, res) {
  res.sendStatus(200);
});

有没有办法取消设置编码?是否有另一种方法来检索原始正文,但在它之后仍然使用 body-parser?

【问题讨论】:

  • 在 bodyParser 之后使用你的中间件?
  • 您在res.sendStatu(200); 中也有错字。
  • 您确定需要设置编码吗?
  • @doublesharp 错字已修复,谢谢!
  • @nicovank 如果我更改中间件顺序,我的自定义中间件会挂起。我想这是因为流已经被消耗了。我正在调查它可能是什么。

标签: node.js body-parser


【解决方案1】:

原来body-parser 有一个verify 选项,可以在读取请求正文时调用函数。该函数接收主体作为缓冲区。

这是一个例子:

var express = require('express');
var bodyParser = require('body-parser')

function verifyRequest(req, res, buf, encoding) {
  // The raw body is contained in 'buf'
  console.log( buf.toString( encoding ) );
};

var app = express();
var listener = app.listen(3000);

// Hook 'verifyRequest' with body-parser here.
app.use(bodyParser.json({ verify: verifyRequest }))

app.post('/webhook/', function (req, res) {
  res.status(200).send("done!");
});

【讨论】:

    【解决方案2】:

    您在“完成”内调用next(),这意味着该流已被使用。相反,为“数据”设置处理程序,然后使用next() 传递请求。 “完成”事件可能在bodyParser 内部处理,因此在它执行后您可以访问req.rawBody。如果不是这种情况,您可以在 req.on('done') 中添加另一个调用 next() 的中间件,以阻止其余的处理,直到您拥有所有数据。

    // custom middleware - req, res, next must be arguments on the top level function
    function myMiddleware(req, res, next) {
      req.rawBody = '';
    
      req.on('data', function(chunk) {
        req.rawBody += chunk;
      });
    
      // call next() outside of 'end' after setting 'data' handler
      next();  
    }
    
    // your middleware
    app.use(myMiddleware);
    
    // bodyparser
    app.use(bodyParser.json())
    
    // test that it worked
    function afterMiddleware(req, res, next) {
      console.log(req.rawBody);
      next();  
    }
    
    app.use(afterMiddleware);
    

    如果您需要访问原始正文,您可能还需要查看bodyParser.raw()。这会将原始正文放入req.body,与bodyParse.json() 相同,但可以根据内容类型有条件地运行 - 请查看options.type

    【讨论】:

    • in your example the inner function is never being called 是的......函数myMiddleware 正在返回函数,他稍后调用它app.use(myMiddleware())
    • 你是对的,但它没有传入req, res, next,所以它们没有在正确的上下文中执行
    • 将中间件处理程序编写为内部函数,允许调用者在设置期间将参数选项传递给中间件。
    • 我对这个解决方案有一个新问题,app.get('/', function (req, res) { }) 不再被调用。
    【解决方案3】:

    我推荐一种不同的方法,因为您当前的方法实际上会消耗消息并且使正文解析器无法读取它(并且同步调用 next 会出现一堆边缘情况错误):

    app.use(bodyParser.json());
    app.use(bodyParser.text({type: '*/*'}));
    

    这会将任何 application/json 请求读取为 JSON,并将其他所有内容读取为文本。

    如果除了文本还必须有JSON对象,建议自己解析:

    app.use(bodyParser.text({type: '*/*'}));
    app.use(myMiddleware);
    
    function myMiddleware(req, res, next) {
        req.rawBody = req.body;
        if(req.headers['content-type'] === 'application/json') {
            req.body = JSON.parse(req.body);
        }
        next();
    }
    

    【讨论】:

    • 我认为自己解析它是要走的路。
    猜你喜欢
    • 2018-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-07
    • 2013-09-13
    相关资源
    最近更新 更多