2016-11-16 77 views
2

我写了Express中间件从请求中检索原始主体,并在body-parser中间件之前设置它。编写express express中间件,在body-parser之前获取原始请求体

我定制的中间件呼吁req.setEncoding('utf8'),但是这将导致以下机身解析器错误:

Error: stream encoding should not be set

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); 
}); 

有没有办法来未设置编码?还有另一种方法可以退出原始身体,但仍然使用身体分析器后?

+1

bodyParser,然后再使用中间件? – nicovank

+0

你在'res.sendStatu(200);'中也有一个错字。 – doublesharp

+0

你确定你需要设置编码吗? – doublesharp

回答

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

+1

'在你的例子中,内部函数永远不会被调用'是的,它是......函数'myMiddleware'正在返回函数,他稍后调用'app.use(myMiddleware())' – nicovank

+0

你是对的,但它不会传入'req,res,next',因此它们不会在正确的上下文中执行 – doublesharp

+0

是的,它们是....这是一个小提琴:https://jsfiddle.net/8zn44d0c/ – nicovank

0

我推荐了不同的方法,因为你目前的做法实际上消耗的消息,并使其无法为身体的解析器读取它(并有通过调用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(); 
} 
+0

我认为自己解析它将会是一条路。 – kiewic

1

事实证明,body-parser验证选项呼叫功能时请求主体具有被读过。该函数将该主体作为缓冲区接收。

下面是一个例子:

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

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

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!"); 
});