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使用verify
callback良好。 在这个代码中,我使用它来获取内容的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) { });
它不在分块的请求主体上工作。