express项目中通常使用body-parser进行post参数的解析,最常用的是其中的json和urlencoded的parser,可分别对以JSON格式的post参数和urlencoeded的post参数进行解析,均可获得一个JSON化的req.body,如:
{
"username": "user",
"password": "pass"
}
body-parser还有一个raw parser,可以获取一个buffer对象的req.body。
通过详细阅读body-parser的源代码,可以知道,各个parser会对req headers及post参数进行一系列的判断和处理,只有满足条件的情况下才对post参数进行解析,解析之前,首先使用raw-body模块对req进行处理,其处理过程是将req作为一个readable stream进行处理,从而得到raw body内容,然后按具体的格式进行解析。
在express项目中,通常顺序调用body-parser所提供的parser,这样当一个parser无法满足post参数解析条件时,还可以使用另一个parser进行解析(在某些特殊的请求中,有可能所有parser均无法解析)。
app.use(bodyParser.raw);
app.use(bodyParser.json);
app.use(bodyParser.urlencoded({
extended: false
});
但body-parser的各个parser在解析的过程中,若对满足解析条件的post参数进行了解析,req作为一个stream对象,已经被消耗,无法再使用另一个parser对post参数解析,也即post参数只能被第一个满足解析条件的parser进行解析。因此即使先后调用raw、json、urlencoded这三个parser,也只能得到一个body,具体格式由各parser的调用次序及post参数满足的解析条件决定。JSON化的body和raw body如同鱼与熊掌,二者不可得兼。
但在有些场合下,可能需要在解析body的同时使用raw body进行其他操作,如某些应用场景下就需要使用raw body参与签名运算以对访问者进行鉴权。
其实body-parser
提供了一个办法在解析post参数的同时获取raw body
,那就是在调用parser的时候传入的参数中带verify回调函数:
app.use(bodyParser.json({
verify: function (req, res, buf, encoding) {
req.rawBody = buf;
}
}));
app.use(bodyParser.urlencoded({
extended: false,
verify: function (req, res, buf, encoding) {
req.rawBody = buf;
}
}));
verify参数本身是用于对请求的校验,当校验失败的时候通过抛出error来中止body-parser的解析动作,在这里被借用来实现post参数raw body的获取。
这样一来,在将post参数解析成JSON化的req.body的同时,body-parser还会将raw body赋值给req.rawBody(当然,内存也占用了两份,这是需要注意的地方,如果应用中有大数据量的POST请求,那可就要注意了)。