Node.js – 使用Express获取原始请求主体

当我使用Express时,我的代码是:

app.use(express.bodyParser()); 

我将如何获得原始请求的身体

编辑2:版本1.15.2的主体parsing器模块引入了原始模式 ,它将主体作为缓冲区返回。 默认情况下,它也会自动处理deflate和gzip解压。 用法示例:

 var bodyParser = require('body-parser'); app.use(bodyParser.raw(options)); app.get(path, function(req, res) { // req.body is a Buffer object }); 

默认情况下, options对象具有以下默认选项:

 var options = { inflate: true, limit: '100kb', type: 'application/octet-stream' }; 

如果你想要你的原始parsing器parsingapplication/octet-stream以外的其他MIMEtypes,你将需要在这里改变它。 它还将支持通配符匹配,例如*/**/application


注意:以下答案适用于Express 4之前的版本,其中中间件仍然与框架捆绑在一起。 现代等价物是body-parser模块,它必须单独安装。

Express中的rawBody属性曾经可用,但自1.5.1版以来已被删除。 为了得到原始的请求体,在使用bodyParser之前,你必须放入一些中间件。 你也可以在这里阅读关于它的GitHub讨论。

 app.use(function(req, res, next) { req.rawBody = ''; req.setEncoding('utf8'); req.on('data', function(chunk) { req.rawBody += chunk; }); req.on('end', function() { next(); }); }); app.use(express.bodyParser()); 

该中间件将从实际的数据stream中读取,并将其存储在请求的rawBody属性中。 然后你可以像这样访问原始的主体:

 app.post('/', function(req, res) { // do something with req.rawBody // use req.body for the parsed body }); 

编辑:看来,这个方法和bodyParser拒绝共存,因为一个会消耗请求stream在另一个之前,导致无论哪一个是第二个永远不会end ,因此永远不会调用next() ,并挂起您的应用程序。

最简单的解决scheme很可能是修改连接的JSONparsing器的第57行中的bodyParser的源代码。 这是修改后的版本的样子。

 var buf = ''; req.setEncoding('utf8'); req.on('data', function(chunk){ buf += chunk }); req.on('end', function() { req.rawBody = buf; var first = buf.trim()[0]; ... }); 

你会在这个位置find该文件:

/node_modules/express/node_modules/connect/lib/middleware/json.js

我有一个解决scheme,与bodyParser,在bodyParser使用verifycallback良好。 在这个代码中,我使用它来获取内容的sha1,并获得原始的正文。

 app.use(bodyParser.json({ verify: function(req, res, buf, encoding) { // sha1 content var hash = crypto.createHash('sha1'); hash.update(buf); req.hasha = hash.digest('hex'); console.log("hash", req.hasha); // get rawBody req.rawBody = buf.toString(); console.log("rawBody", req.rawBody); } })); 

我在Node.js和express.js(昨天开始,字面意思!)是新的,所以我想听听这个解决scheme的意见。

请小心其他的答案,因为如果你还想支持json,urlencoded等,它们将无法正常使用bodyParser。为了使它与bodyParser一起工作,你应该限制你的处理器只注册Content-Type头( s)你关心,就像bodyParser本身一样。

要获取具有Content-Type: "text/plain"的请求的原始内容到req.rawBody您可以:

 app.use(function(req, res, next) { var contentType = req.headers['content-type'] || '' , mime = contentType.split(';')[0]; if (mime != 'text/plain') { return next(); } var data = ''; req.setEncoding('utf8'); req.on('data', function(chunk) { data += chunk; }); req.on('end', function() { req.rawBody = data; next(); }); }); 

这是六氰菊酯的答案上面的变化。 这个中间件也处理'data'事件,但是不会在调用next之前等待数据被消耗。 这样这个中间件和bodyParser可以共存,并行消耗stream。

 app.use(function(req, res, next) { req.rawBody = ''; req.setEncoding('utf8'); req.on('data', function(chunk) { req.rawBody += chunk; }); next(); }); app.use(express.bodyParser()); 

这个解决scheme为我工作:

 var rawBodySaver = function (req, res, buf, encoding) { if (buf && buf.length) { req.rawBody = buf.toString(encoding || 'utf8'); } } app.use(bodyParser.json({ verify: rawBodySaver })); app.use(bodyParser.urlencoded({ verify: rawBodySaver, extended: true })); app.use(bodyParser.raw({ verify: rawBodySaver, type: '*/*' })); 

当我使用req.on('data', function(chunk) { }); 它不在分块的请求主体上工作。