Expressjs raw body
Asked Answered
S

12

72

How can I access raw body of request object given to me by expressjs?

var express = require('./node_modules/express');
var app = express.createServer();
app.post('/', function(req, res)
{
    console.log(req.body); //says 'undefined'
});
app.listen(80);
Subtraction answered 29/3, 2012 at 6:33 Comment(8)
A little most context here would be useful. What type of data are you expecting in the body? Are you trying to read form data, or something more complicated.Deboer
I'm not sure I understand how that impacts on the way that I can get raw body. Let's say that it's just some unknown binary data.Subtraction
Well for one, I wanted to make sure it wasn't just something you could just use bodyParser for. And if the data was binary then it doesn't make sense to make it a string, so you'd want to aggregate buffers instead. And if it's binary, then you should probably not be aggregating it at all anyway since you should try to immediately pipe the data somewhere.Deboer
Also, you should just be able to do require('express'). It will find that module all by itself.Deboer
But what if the data is JSON or XML?Subtraction
Did you solve this? I need to get the rawBody from the request as well. I have XML data coming in. It sucks that .rawBody was removed from bodyParser.Johore
Tarandeep Gill, you're not gonna believe what I did, lol, but I just modified bodyParser.js source code and brought back that line with rawBody:) So now I have it. Though it seams to me just not right because in this scenario my code invokes bodyParser only to get this rawBody which causes executing a lot of code that I don't need. It's not right from performance point of view.Subtraction
@Stewe's answer says how to solve this without modifying bodyParser...Deboer
D
22

Default express does not buffer data unless you add middleware to do so. The simple solution is to follow the example in @Stewe's answer below, which would just concatenate all of the data yourself. e.g.

var concat = require('concat-stream');
app.use(function(req, res, next){
  req.pipe(concat(function(data){
    req.body = data;
    next();
  }));
});

The downside of this is that you have now moved all of the POST body content into RAM as a contiguous chunk, which may not be necessary. The other option, which is worth considering but depends on how much data you need to process in the post body, would be to process the data as a stream instead.

For example, with XML you could use an XML parser that supports parsing XML as it comes in as chunks. One such parser would be XML Stream. You do something like this:

var XmlStream = require('xml-stream');

app.post('/', function(req, res) {
  req.setEncoding('utf8');
  var xml = new XmlStream(req);
  xml.on('updateElement: sometag', function(element) {
    // DO some processing on the tag
  });
  xml.on('end', function() {
    res.end();
  });
});
Deboer answered 29/3, 2012 at 18:43 Comment(7)
Ok, I'll mark your answer as accepted. But this conversation wouldn't have happened if someone hadn't removed the line that saves original body in request object.Subtraction
Man, we're here to help, there is no reason to sound so annoyed. Blindly buffering data in doesn't make sense, and doing it yourself is easy if you actually take the time to learn how Node works. Every answer here explains how to do this.Deboer
I'm annoyed by the fact that bodyParser collects body chunks anyway, but doesn't give them to me if they cannot be parsed by bodyParser. That's illogical behaviour. I think that dealing with streams should be hidden from developer when using middleware framework.Subtraction
The only chunks bodyParser collects are ones with matching content type allowed by bodyParser, so it should never fail. If it's actually getting parser errors, then you are using the wrong content type. And if you have a custom content type, then adding your own parser middleware for that content-type is what you should do, not hack the bodyParser middleware.Deboer
Since express 4 and body-parser 1.15.2 you can turn req.body into a buffer. See this answerBozen
concat is not definedLaterite
@Laterite Are you missing the var concat = require('concat-stream'); part of this code?Deboer
D
63

Something like this should work:

var express = require('./node_modules/express');
var app = express.createServer();
app.use (function(req, res, next) {
    var data='';
    req.setEncoding('utf8');
    req.on('data', function(chunk) { 
       data += chunk;
    });

    req.on('end', function() {
        req.body = data;
        next();
    });
});

app.post('/', function(req, res)
{
    console.log(req.body);
});
app.listen(80);
Darrickdarrill answered 29/3, 2012 at 7:15 Comment(9)
You suggest me to do the same work that ExpressJs already does!There must be a way to pull that damn raw body out of request.Subtraction
The bodyParser() middleware used to have .rawBody but that has been removed: github.com/senchalabs/connect/commit/…Darrickdarrill
Yep. So is there no way to get raw body??Subtraction
Wait, does it mean that ExpressJs doesn't collect body chunks without bodyParser??Subtraction
@AndreyKon Nope. That's generally not something you'd want. Node is very focused on using streams where possible.Deboer
I've found that concatenating the raw chunks like that usually causes my media uploads to unplayable/corrupt files, just fyi in my experienceTripartite
It seems like this solution doesn't work anymore in Express 4.Rafaello
You might also want to check the req.method first, for instance to parse only the GET / POST methods but not the OPTIONS method.Malchy
You need to install a package just to tell express not to mess with the request body?Intoxication
Q
51

Using the bodyParser.text() middleware will put the text body in req.body.

app.use(bodyParser.text({type: '*/*'}));

If you want to limit processing the text body to certain routes or post content types, you can do that too.

app.use('/routes/to/save/text/body/*', bodyParser.text({type: 'text/plain'})); //this type is actually the default
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

If you want a raw Buffer, you can use bodyParse.raw().

app.use(bodyParser.raw({type: '*/*'}));

Note: this answer was tested against node v0.12.7, express 4.13.2, and body-parser 1.13.3.

Quinquefid answered 12/8, 2015 at 22:3 Comment(6)
This worked for me. I needed to process xml bodies, so I used the following line: app.use(bodyParser.text({ type: '*/xml' })); which populated my req.body nicely.Macron
this should be the correct answer. the rest are outdated.Aenneea
app.use(bodyParser.raw({type: '*/*'})); if you want the binary data as a BufferWindward
This answer is still a bit confusing (but I upvoted since it was still helpful). The code example is using text() yet you mention using raw().Rostrum
Yeah which is it, text() or raw()?Sheets
Apologies, raw() gives a Buffer, text() parses as text and gives a string. For this specific question they'd want text(), I'll update the answer.Quinquefid
H
29

Put the following middleware before bodyParser middleware. It'll collect raw body data in request.rawBody and won't interfere with bodyParser.

app.use(function(req, res, next) {
    var data = '';
    req.setEncoding('utf8');
    req.on('data', function(chunk) { 
        data += chunk;
    });
    req.on('end', function() {
        req.rawBody = data;
        next();
    });
});
app.use(express.bodyParser());
Housekeeper answered 26/11, 2012 at 13:25 Comment(11)
I think that you need to move the next(); call inside req.on('end'.. callback function.Lues
As @user1144642 noticed, the original code was correct. This is event based code, if you block the execution and consume all data here then bodyParser will not get any data and will hang forever. next() outside passes control next to bodyParser thus allows it to bind event handler and receive data simultaneously.Housekeeper
I tried the code the way it was originally posted and the req.rawBody variable didn't get filled by the time I wanted to use it. Is there a trick I'm missing?Lues
@Lues req.rawBody will be filled as soon as request received. The idea here is to use it together with bodyParser so they don't interfere. In the same time, bodyParser will not pass control to next() middleware until it consume the request, so any middleware executed after bodyParser will be able to access rawBody. This code is very specific, and functions order here is very important.Housekeeper
The only way I made this work, was by putting the next() inside the 'end' function. I don't really understand what'd be wrong with that.Nanoid
@hookdump I don't know what was wrong, but this code worked fine for me on old connect and now it doesn't work on the latest version. I fixed the code and put next() inside of end handler.Housekeeper
For me this only works if I move next() outside of req.on('end', ...)Pulsatory
@Pulsatory do you use latest express?Housekeeper
`app.use(function(req, res, next) { var req.rawData = ''; req.setEncoding('utf8'); req.on('data', function(chunk) { req.rawData += chunk; }); next(); }); app.use(express.bodyParser());Bonaparte
yes, like Andy said, it real hangs, no data for bodyParser anymoreUnderpinnings
If you move next out of the 'end' event you will call downstream middleware before you have all the data!Vestavestal
D
22

Default express does not buffer data unless you add middleware to do so. The simple solution is to follow the example in @Stewe's answer below, which would just concatenate all of the data yourself. e.g.

var concat = require('concat-stream');
app.use(function(req, res, next){
  req.pipe(concat(function(data){
    req.body = data;
    next();
  }));
});

The downside of this is that you have now moved all of the POST body content into RAM as a contiguous chunk, which may not be necessary. The other option, which is worth considering but depends on how much data you need to process in the post body, would be to process the data as a stream instead.

For example, with XML you could use an XML parser that supports parsing XML as it comes in as chunks. One such parser would be XML Stream. You do something like this:

var XmlStream = require('xml-stream');

app.post('/', function(req, res) {
  req.setEncoding('utf8');
  var xml = new XmlStream(req);
  xml.on('updateElement: sometag', function(element) {
    // DO some processing on the tag
  });
  xml.on('end', function() {
    res.end();
  });
});
Deboer answered 29/3, 2012 at 18:43 Comment(7)
Ok, I'll mark your answer as accepted. But this conversation wouldn't have happened if someone hadn't removed the line that saves original body in request object.Subtraction
Man, we're here to help, there is no reason to sound so annoyed. Blindly buffering data in doesn't make sense, and doing it yourself is easy if you actually take the time to learn how Node works. Every answer here explains how to do this.Deboer
I'm annoyed by the fact that bodyParser collects body chunks anyway, but doesn't give them to me if they cannot be parsed by bodyParser. That's illogical behaviour. I think that dealing with streams should be hidden from developer when using middleware framework.Subtraction
The only chunks bodyParser collects are ones with matching content type allowed by bodyParser, so it should never fail. If it's actually getting parser errors, then you are using the wrong content type. And if you have a custom content type, then adding your own parser middleware for that content-type is what you should do, not hack the bodyParser middleware.Deboer
Since express 4 and body-parser 1.15.2 you can turn req.body into a buffer. See this answerBozen
concat is not definedLaterite
@Laterite Are you missing the var concat = require('concat-stream'); part of this code?Deboer
A
16
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;
    }
}));
Amandaamandi answered 30/11, 2015 at 2:32 Comment(3)
terrific answer, works great thanks (note: this uses body-parser module)Ingeborg
Thanks, this helped me also! Best answer here. :-)Meilen
I solved it using this flaviocopes.com/express-get-raw-body but up voted this answer bcz it's the same thingCaddish
B
10

All the answers seems outdated, if anyone still struggling with this then express has built-in Express raw middeware.

This middleware is available in Express v4.16.0 onwards. This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser.

var express = require("express");
var app = express();

app.use(express.raw({ type: "*/*" }))

app.post("/", (req, res) => {
  // req.body = JSON.parse(req.body); // To parse JSON if needed (in-case)
  console.log(req.body);
  res.end();
});

app.listen(3000, (err) => {
if(!err) console.log("App running!!")
});
Balcer answered 13/1, 2021 at 13:33 Comment(1)
Is this analog to bodyParser.raw( [options] )?Induce
J
9

So, it seems like Express's bodyParser only parses the incoming data, if the content-type is set to either of the following:

  1. application/x-www-form-urlencoded
  2. application/json
  3. multipart/form-data

In all other cases, it does not even bother reading the data.

You can change line no. 92 of express/node_modules/connect/lib/middleware/bodyParser.js from

} else {
        next();
}

To:

} else {
        var data='';
        req.setEncoding('utf8');
        req.on('data', function(chunk) { 
           data += chunk;
        });

        req.on('end', function() {
            req.rawBody = data;
            next();
        });
}

And then, read req.rawBody from your code.

Johore answered 29/3, 2012 at 17:52 Comment(1)
Modifying connect is really not a great way to do this, though it'll work. As @Stewe's answer shows, you can just as easily add your own middleware, and they you don't have to modify any external libraries.Deboer
W
6

If you want the body as a buffer:

var rawParser = function(req, res, next) {
    var chunks = [];
    req.on('data', function(chunk) { 
        chunks.push(chunk)
    });
    req.on('end', function() {
        req.body = Buffer.concat(chunks);
        next();
    });
}

or

var rawParser = bodyParser.raw({type: '*/*'});

and then:

app.put('/:name', rawParser, function(req, res) {
  console.log('isBuffer:', Buffer.isBuffer(req.body));
})

or for all routes:

app.use(bodyParser.raw({type: '*/*'}));
Windward answered 28/5, 2016 at 3:54 Comment(0)
C
5

It seems this has become a lot easier now!

The body-parser module is able to parse raw and text data now, which makes the task a one-liner:

app.use(bodyParser.text({type: 'text/plain'}))

OR

app.use(bodyParser.raw({type: 'application/binary'}))

Both lines simply fill the body property, so get the text with res.body. bodyParser.text() will give you the UTF8 string while bodyParser.raw() will give you the raw data.

This is the full code for text/plain data:

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

app.use(bodyParser.text({type: 'text/plain'}))

app.post('/', function (req, res, next) {
    console.log('body:\n' + req.body)

    res.json({msg: 'success!'})

    next()
})

See here for the full documentation: https://www.npmjs.com/package/body-parser

I used express 4.16 and body-parser 1.18

Ciel answered 7/3, 2018 at 10:55 Comment(0)
L
4

If you are having trouble with the above solutions interfering with normal post requests, something like this might help:

app.use (function(req, res, next) {
    req.rawBody = '';
    req.setEncoding('utf8');
    req.on('data', function(chunk) { req.rawBody += chunk });
});

More info & source: https://github.com/visionmedia/express/issues/897#issuecomment-3314823

Lues answered 22/12, 2012 at 5:31 Comment(1)
You forgot the next(); at the end. It worked for me when adding it.Lozengy
G
3

BE CAREFUL with those other answers as they will not play properly with bodyParser if you're looking to also support json, urlencoded, etc. To get it to work with bodyParser you should condition your handler to only register on the Content-Type header(s) you care about, just like bodyParser itself does.

To get the raw body content of a request with Content-Type: "text/xml" into req.rawBody you can do:

app.use(function(req, res, next) {
  var contentType = req.headers['content-type'] || ''
    , mime = contentType.split(';')[0];

  if (mime != 'text/xml') {
    return next();
  }

  var data = '';
  req.setEncoding('utf8');
  req.on('data', function(chunk) {
    data += chunk;
  });
  req.on('end', function() {
    req.rawBody = data;
    next();
  });
});
Giuliana answered 4/4, 2014 at 1:7 Comment(0)
P
0

When sending the request be sure to add this header:

'Content-Type': 'application/json'
Paulinepauling answered 10/1, 2022 at 18:17 Comment(1)
That could only be useful if there was a middleware being used which looked for a JSON content-type and then served up the data as plain text instead of parsing it as JSON. The question shows us that no middleware is used, let alone one with that very weird requirement.Serle

© 2022 - 2024 — McMap. All rights reserved.