Node.js-使用Express获取原始请求正文


Answers:


89

编辑2:正文解析器模块的1.15.2版引入了原始模式,该模式将正文作为Buffer返回。默认情况下,它还会自动处理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'
};

如果您希望原始解析器解析以外的其他MIME类型application/octet-stream,则需要在此处进行更改。它还将支持通配符匹配,例如*/**/application


注意:以下答案适用于Express 4之前的版本,其中中间件仍与框架捆绑在一起。现代等效项是主体解析器模块,必须单独安装。

rawBodyExpress中的属性曾经可用,但是从版本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());

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

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

编辑:似乎此方法和bodyParser拒绝共存,因为一个方法将在另一个方法之前消耗请求流,从而导致第二个方法永远不会触发end,从而永远不会调用next(),并挂起您的应用程序。

最简单的解决方案很可能是修改bodyParser的源,您可以在Connect的JSON解析器的第57行中找到该源。这就是修改后的版本。

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

您可以在以下位置找到文件:

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


看来我们无法做到这一点。如果添加了这些代码,则不会触发\ node_modules \ express \ node_modules \ connect \ lib \ middleware \ urlencoded.js中的事件。req.on(“ data”),req.on(“ end”)未触发
haitao_wu 2013年

添加您的代码后,我将使用此代码app.post(“ / ajax”,function(req,res){res.send('hello world,post');});处理我的帖子。当我的请求的内容类型为application / x-www-form-urlencoded时,服务器将不会响应“ hello world,post”
haitao_wu 2013年

文件的位置在我的情况下是不正确的。。我在express(> 4.0.0)的node_modules中没有连接模块尚未找到新的位置
Sam Vloeberghs 2014-4-27

Connect在Express 4中不是依赖项,因此不包含Body Parser模块。如果您仍然需要它,可以在这里找到它。

1
@hexacyanide您能否更新您的答案并提供对最新人体分析器中间件的引用?现在,该模块包括raw-body-parser中间件。这对寻求寻找原始方法的Google员工很有帮助。
eAbi 2015年

47

使用bodyParser中的verify回调,我得到了一个与bodyParser配合良好的解决方案。在这段代码中,我正在使用它来获取内容的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的新手(从昨天开始,从字面上看!),所以我想听听对此解决方案的评论。


3
我真的很喜欢这个解决方案。我只是req.rawBody = buf.toString();将其余部分包括在内,并从verify功能中删除了其余部分,因为这是我所需要的,并且运行良好。无需更改bodyParser源代码!
格雷格

+1,但我现在的问题是,我需要一个异步函数来验证此请求是否以前已发送过:/
Renato Gama 2015年

3
非常好。我可以建议req.rawBody = buf.toString(encoding);

2
这将捕获只application/json请求
帕维尔Evstigneev

35

此解决方案为我工作:

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) { });不能在分块的请求正文上工作时。


这处理了请求各个部分中传入数据的每种主要情况。
TWright,2016年

2
我试图为Shopify应用程序Webhook验证hmac,这对我有用。我大致遵循以下示例:gist.github.com/andjosh/5c4f0244914adfd312e4
乍得·约翰逊

29

请谨慎处理其他答案,因为如果您还希望支持json,urlencoded等,它们将无法在bodyParser上正常播放。要使其与bodyParser一起使用,您应限制您的处理程序仅在 Content-Type标头上就像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();
  });
});

3
+1。我尝试了上述解决方案之一,然后所有的GET和json帖子都失败了。上面的解决方案在技术上对这个问题是正确的,但是如果您要处理的多种形式的数据请求具有多种形式,则将需要此解决方案。

这里的数据是什么?是我们从用户界面发送的变量吗?
萨拉斯·亚里亚

app.use(bodyParser.urlencoded({limit: '80mb', extended: true})); app.use(bodyParser.json({limit: '80mb'})); app.use(bodyParser.raw({type: 'application/octet-stream'})) 这也可以。
Soumya Kanti

15

这是上述六氰化物答案的一种变化。该中间件还处理“数据”事件,但在调用“下一个”之前不等待数据被消耗。这样,中间件和bodyParser可以共存,并行使用流。

app.use(function(req, res, next) {
  req.rawBody = '';
  req.setEncoding('utf8');

  req.on('data', function(chunk) { 
    req.rawBody += chunk;
  });

  next();
});
app.use(express.bodyParser());


2
这似乎不适用于长形的​​身体,后者会早早切断。
亚当·洛克哈特2014年

工作完美,救了我。谢谢。
hakazvaka

我确认这也适用于大文件。我尝试发送1.5MB的文本文件,并且正确接收了整个数据。谢谢
ATOzTOA

@AdamLockhart-您的请求被削减了多大?
UpTheCreek '16

@UpTheCreek,已经有一段时间了。不确定。我最新的资料没有使用此代码段,但如果其他人未报告任何问题,则可能是已修复的错误。
亚当·洛克哈特

-1

使用body-parser解析物体的形状:

app.use(bodyParser.text());

app.use(bodyParser.urlencoded());

app.use(bodyParser.raw());

app.use(bodyParser.json());

即。如果您应该获取原始文本文件,请运行.text()

那就是body-parser当前支持的功能

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.