我编写了一个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);
});
有没有办法取消编码?有没有另一种方法来退出原始身体,但仍然使用身体解析器?
答案 0 :(得分:3)
您正在“完成”内部调用next()
,这意味着该流已被使用。相反,为“数据”设置处理程序,然后使用next()
传递请求。 “完成”事件很可能在bodyParser
内处理,因此在执行后您可以访问req.rawBody
。如果不是这种情况,您可以添加另一个在next()
内调用req.on('done')
的中间件来保持其余的处理,直到您拥有所有数据。
// 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
。
答案 1 :(得分:3)
事实证明,body-parser有一个验证选项,可以在读取请求正文时调用函数。该函数接收主体作为缓冲区。
以下是一个例子:
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 :(得分:0)
我推荐一种不同的方法,因为你当前的方法实际上消耗了这个消息并且使得body-parser无法读取它(并且通过同步调用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();
}