704

How do you extract form data (form[method="post"]) and file uploads sent from the HTTP POST method in Node.js?

I've read the documentation, googled and found nothing.

function (request, response) {
    //request.post????
}

Is there a library or a hack?

nabster
  • 1,319
  • 2
  • 19
  • 31
Ming-Tang
  • 16,475
  • 8
  • 35
  • 73

29 Answers29

740

You can use the querystring module:

var qs = require('querystring');

function (request, response) {
    if (request.method == 'POST') {
        var body = '';

        request.on('data', function (data) {
            body += data;

            // Too much POST data, kill the connection!
            // 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
            if (body.length > 1e6)
                request.connection.destroy();
        });

        request.on('end', function () {
            var post = qs.parse(body);
            // use post['blah'], etc.
        });
    }
}

Now, for example, if you have an input field with name age, you could access it using the variable post:

console.log(post.age);
nbro
  • 12,226
  • 19
  • 85
  • 163
Casey Chu
  • 22,797
  • 9
  • 37
  • 59
  • 9
    @thejh Hm, that's a good point. It shouldn't be difficult to add that, though, so I'll leave it out of the example to keep things simple. – Casey Chu Dec 27 '11 at 06:48
  • 81
    node.js web server development is plagued with middlewarez that require you to study them for hours to save you minutes worth of coding. Let alone the scant documentation almost all of them offer. And your application ends up relying on the criteria of other people, not your's. Plus any number of performance issues. – Juan Lanus Apr 02 '13 at 13:16
  • 5
    `var POST = qs.parse(body); // use POST` only for noobs like me: when the name of the input text field is "user", `Post.user` will show the data of that field. e.g. `console.log(Post.user);` – Michael Moeller May 07 '13 at 22:12
  • 6
    You could also use the `readable`callback instead of building the data into a body string. Once it is fired, the body is available through `request.read();` – Thomas Fankhauser Jun 26 '13 at 11:25
  • 5
    Notice that `req.connection.destroy();` **doesn't prevent the callbacks from being executed!** For example the "on end" callback will be executed with the truncated body! This is not probably what you want... – collimarco Oct 27 '14 at 19:27
  • @collimarco Easily fixable with `return` – eenblam Jun 16 '15 at 13:19
  • 4
    How to handle file field with this scenario? That is ``. Here how we can retrieve file data with `qs.parse(body)`. When I tried with `qs` it is returning as `{"-----------------------------189644229932\r\nContent-Disposition: form-data;.... -189644229932--\r\n":""}`. How to handle post form file data in pure node.js? – Justin John Sep 11 '15 at 09:26
  • 1
    @Ben it's an async callback, the `return` doesn't do nothing in this situation – Manuel Di Iorio Jan 15 '16 at 18:52
  • It is worth noting that you can only parse flat data this way. Form elements with names such as name="user[name]", name="user[email]" etc ... will not parse correctly. So while this solution is simple and doesn't use a library which I like, it has indeed very limited use. – Geza Turi May 11 '16 at 11:50
  • @CaseyChu isn't type of data in "data" event handler (of request object) of type Buffer, how come concatenation works? – gmoniava Nov 16 '16 at 12:55
  • @GiorgiMoniava It was a string back in 2010 :) – Casey Chu Dec 25 '16 at 09:26
  • @CaseyChu ah ok maybe you wanna highlight that in your answer :) – gmoniava Dec 25 '16 at 12:04
  • 2
    This does not work for me .. I really want to know the vanilla Node way of doing this, however it is not responding for me. – JohnSnow Feb 07 '17 at 06:07
  • @JuanLanus indeed, other languages like PHP have this feature integrated and we can get easily a POST parameter without using a third-party library like Express for Node.js. At least this example shows that we can do it also in Node.js with built-in modules, without using any middleware / third-party package. – baptx Jul 21 '18 at 22:50
  • 1
    @baptx Yes, PHP es geared to handle HTTP requests of all kinds, nodejs is more generic, an unopinionated engine for running JS programs. IMO PHP is comparable to the (JS + express) bundle: a language plus an HTTP handling framework. Actually, PHP + Apache. In the last years Express evolved from a smartass developer's brilliant project into a coherently managed company, and in this evolution it became a much more usable application (from the standpoint of the developer). – Juan Lanus Jul 23 '18 at 12:35
  • @baptx + One of the goals of the express evolution was to publish good docs. I'm using express again after a number of years and had a nice surprise. For example it's more self-contained instead of relying in the high number of suspicious middlewares I mentioned time ago. – Juan Lanus Jul 23 '18 at 12:36
  • @JuanLanus it would be nice if Node.js adds an easier way to receive POST data, built-in and integrated in the official Node.js API, so it can better compare to PHP without any additional library. This could be interesting for apps that don't want to use a framework just for a few features. – baptx Aug 06 '18 at 14:59
  • @baptx: IMO it's not going to happen, for a good reason. Node is not a specialized HTTP requests manager like Apache, nginx, PHP. Its just an unopinionated JS motor; one of its applications is to implement web servers. For this purpose you can either use Express (or other similar thing), or do it on top of a barebones node. In the last case you have to deal with the intricacies of the HTTP POST method, meaning you'll write the equivalent of the middleware you skipped. Which is OK. If I did it I'd peep into the body parsing code available :-) – Juan Lanus Aug 07 '18 at 15:16
  • Post data might be binary? – jgmjgm Oct 15 '19 at 09:39
  • For safety also mention timeout? – jgmjgm Oct 15 '19 at 09:39
  • If you want to take action on the response body based on a POST value and the POST is empty (eg: want to show a list of POST values like in PHP `print_r($_POST)`) this will never send the response, because as there is no start, there is no 'end'. – Alguem Meugla Mar 23 '21 at 15:06
  • Nevermind. The problem was a lack of a `res.end()`. – Alguem Meugla Mar 23 '21 at 15:35
  • This is the stronger answer than the one suggesting usage of Express. – Steven Apr 15 '21 at 01:25
617

If you use Express (high-performance, high-class web development for Node.js), you can do this:

HTML:

<form method="post" action="/">
    <input type="text" name="user[name]">
    <input type="text" name="user[email]">
    <input type="submit" value="Submit">
</form>

API client:

fetch('/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        user: {
            name: "John",
            email: "john@example.com"
        }
    })
});

Node.js: (since Express v4.16.0)

// Parse URL-encoded bodies (as sent by HTML forms)
app.use(express.urlencoded());

// Parse JSON bodies (as sent by API clients)
app.use(express.json());

// Access the parse results as request.body
app.post('/', function(request, response){
    console.log(request.body.user.name);
    console.log(request.body.user.email);
});

Node.js: (for Express <4.16.0)

const bodyParser = require("body-parser");

/** bodyParser.urlencoded(options)
 * Parses the text as URL encoded data (which is how browsers tend to send form data from regular forms set to POST)
 * and exposes the resulting object (containing the keys and values) on req.body
 */
app.use(bodyParser.urlencoded({
    extended: true
}));

/**bodyParser.json(options)
 * Parses the text as JSON and exposes the resulting object on req.body.
 */
app.use(bodyParser.json());

app.post("/", function (req, res) {
    console.log(req.body.user.name)
});
TuukkaH
  • 43
  • 4
Baggz
  • 16,239
  • 4
  • 35
  • 25
  • 48
    The functionality is actually in the BodyParser module in connect, if you want to use a lower level entry point. – Julian Birch Jun 20 '11 at 06:59
  • 16
    I'm confused. How does name="user[email]" correspond to request.body.email ? – sbose Apr 16 '12 at 14:19
  • 3
    req.body.user == {name: 'some value', email: 'some value'}. It looks like there is a typo above – Stephen May 12 '12 at 19:30
  • 41
    God!! am getting mad having to read 3 doumentations at the same time for the same framework :/ http://nodejs.org/api/http.html , http://www.senchalabs.org/connect/ & http://expressjs.com/guide.html – Salman von Abbas Jul 19 '12 at 10:58
  • 16
    This didn't work for me until I added `app.use(express.bodyParser());`. – pettys May 09 '13 at 16:32
  • Could somebody point to the place in Express that handles the RAM flooding vulnerability present in using the plain `http` module? – Steven Lu Jul 23 '13 at 02:48
  • 10
    Why is this a valid answer if he/she has not asked about Express? – Didac Perez Parera Sep 18 '13 at 07:54
  • I'm sorta confused. Your post is about log files (i.e. disk) filling up. Seems like "ram flooding" is a bit different. Also, confused about why my comment is here and not under the actual answer that mentions "ram flooding". Thanks for the link though. – Steven Lu Nov 27 '13 at 04:13
  • 2
    @pettys bodyParser added to above script. – Prusprus Apr 07 '14 at 18:47
  • app.use(express.bodyParser(); is missing a parenthesis – Jim Jones Apr 27 '14 at 21:24
  • how would you receive the raw body value, is it part of the http specification that message bodies must be url parsable? – Nick Sotiros Apr 29 '14 at 01:40
  • 2
    in version 4 of express, you have to install body-parser npm module, require it. Body parser is no longer present as a method in express package. – Capaj May 02 '14 at 00:58
  • And in express 4 you don't need to bodyParser() for this task since it's a security risk because it allows multipart uploads. You could just app.use(bodyParser.urlencoded({extended: true})). If you need to parse json too, add app.use(bodyParser.json()). – rkulla Jul 14 '14 at 03:48
  • 3
    question was "How do you extract POST data in node.js?" not in express js! So using bodyParser() will not suffice cases where you don't use express. – Andrew Shatnyy Aug 06 '14 at 16:51
  • 23
    Express is to node what jQuery is to client side JS. Every time I google help for node I get these lame "use express!" answers. Is it really so difficult to parse post data that it justifies installing an entire web framework? – Shawn Whinnery Oct 16 '14 at 00:09
  • user[name] -> request.body.user.name doesn't work for me, I end up got {"user[name]", 'blahblah'}, doesn't express4. support this any more? – Rob L Mar 02 '15 at 15:16
  • 7
    Not useful unless you use express. I'd downvote if I could. – Fabian Lauer Aug 23 '15 at 15:41
  • 4
    This answer is outdated and wrong (Express does not include a bodyParser anymore). Casey Chu is the one that posted the correct answer. – ecarrizo Sep 21 '15 at 16:00
  • Don't follow this answer unless you want a ton of dependencies installed as well. Use this answer instead: https://stackoverflow.com/a/4310087/4808079 – Seph Reed Jul 22 '17 at 22:40
  • This is amazing. Thank you. – AndrewLeonardi Oct 21 '17 at 17:04
  • 2
    I didn't came to this question to find answer using Express.js – Amit Shah Nov 22 '17 at 10:34
  • 1
    @Baggz saved my day by mentioning the post 4.0 and pre 4.0 express update parts. – vibhor vaish Aug 25 '19 at 12:11
  • 2
    app.use(express.urlencoded()); was added in v.4.16.0. It uses body-parser module (deprecated). To avoid the problem, use app.use(express.urlencoded({extended:true})) or {extended:false} for qs or querystring library, respectively – vess Sep 03 '19 at 19:35
  • 2020 now it says 'body-parser deprecated undefined extended: provide extended option' – Aleksandar Pavić Feb 11 '20 at 13:18
  • As of recent update `express.bodyParser()` is the alternative for the npm `body-parser` – Johnty Nov 26 '20 at 12:58
  • 1
    I downvoted this answer since all node js developers use Express as a crutch. – Steven Apr 15 '21 at 01:24
170

A lot of answers here are not good practices anymore or don't explain anything, so that's why I'm writing this.

Basics

When the callback of http.createServer is called, is when the server have actually received all the headers for the request, but it's possible that the data have not been received yet, so we have to wait for it. The http request object(a http.IncomingMessage instance) is actually a readable stream. In readable streams whenever a chunk of data arrives, a data event is emitted(assuming you have registered a callback to it) and when all chunks have arrived an end event is emitted. Here's an example on how you listen to the events:

http.createServer((request, response) => {
  console.log('Now we have a http message with headers but no data yet.');
  request.on('data', chunk => {
    console.log('A chunk of data has arrived: ', chunk);
  });
  request.on('end', () => {
    console.log('No more data');
  })
}).listen(8080)

Converting Buffers to Strings

If you try this you will notice the chunks are buffers. If you are not dealing with binary data and need to work with strings instead I suggest use request.setEncoding method which causes the stream emit strings interpreted with the given encoding and handles multi-byte characters properly.

Buffering Chunks

Now you are probably not interested in each chunk by it's own, so in this case probably you want to buffer it like this:

http.createServer((request, response) => {
  const chunks = [];
  request.on('data', chunk => chunks.push(chunk));
  request.on('end', () => {
    const data = Buffer.concat(chunks);
    console.log('Data: ', data);
  })
}).listen(8080)

Here Buffer.concat is used, which simply concatenates all buffers and return one big buffer. You can also use the concat-stream module which does the same:

const http = require('http');
const concat = require('concat-stream');
http.createServer((request, response) => {
  concat(request, data => {
    console.log('Data: ', data);
  });
}).listen(8080)

Parsing Content

If you are trying to accept HTML forms POST submission with no files or handing jQuery ajax calls with the default content type, then the content type is application/x-www-form-urlencoded with utf-8 encoding. You can use the querystring module to de-serialize it and access the properties:

const http = require('http');
const concat = require('concat-stream');
const qs = require('querystring');
http.createServer((request, response) => {
  concat(request, buffer => {
    const data = qs.parse(buffer.toString());
    console.log('Data: ', data);
  });
}).listen(8080)

If your content type is JSON instead, you can simply use JSON.parse instead of qs.parse.

If you are dealing with files or handling multipart content type, then in that case, you should use something like formidable which removes all the pain from dealing with it. Have a look at this other answer of mine where I have posted helpful links and modules for multipart content.

Piping

If you don't want to parse the content but rather pass it to somewhere else, for example send it to another http request as the data or save it to a file I suggest piping it rather than buffering it, as it'll be less code, handles back pressure better, it'll take less memory and in some cases faster.

So if you want to save the content to a file:

 http.createServer((request, response) => {
   request.pipe(fs.createWriteStream('./request'));
 }).listen(8080)

Limiting the Amount of Data

As other answers have noted keep in my mind that malicious clients might send you a huge amount of data to crash your application or fill your memory so to protect that make sure you drop requests which emit data pass a certain limit. If you don't use a library to handle the incoming data. I would suggest using something like stream-meter which can abort the request if reaches the specified limit:

limitedStream = request.pipe(meter(1e7));
limitedStream.on('data', ...);
limitedStream.on('end', ...);

or

request.pipe(meter(1e7)).pipe(createWriteStream(...));

or

concat(request.pipe(meter(1e7)), ...);

NPM Modules

While I described above on how you can use the HTTP request body, for simply buffering and parsing the content, I suggesting using one of these modules rather implementing on your own as they will probably handle edge cases better. For express I suggest using body-parser. For koa, there's a similar module.

If you don't use a framework, body is quite good.

danronmoon
  • 3,613
  • 5
  • 32
  • 55
Farid Nouri Neshat
  • 26,357
  • 6
  • 67
  • 109
  • 1
    Thanks, I used your code and I got mysterious duplicated messages. Could it be that the variable `request` is re-used and the `request.on('end')` got invoked multiple times? How can I avoid that? – Yan King Yin Mar 28 '17 at 00:11
  • 1
    I can't tell why without seeing your code. Note that for every request, `request.on('end', ...)` will be called. – Farid Nouri Neshat Mar 28 '17 at 01:14
  • 1
    It's probably unrelated to your code, I'm doing server-sent events and may have screwed it up... your code is working fine, thanks anyway :) – Yan King Yin Mar 28 '17 at 01:16
  • 1
    How does this effect performance when compared to processing a GET request without an 'end' handler, ie without buffering chunks? – JSON Sep 05 '18 at 18:05
  • @JSON I'm not sure what are you asking. If you are processing the request body you just have to wait till all the chunks are arrived, or you can process them as they arrive. – Farid Nouri Neshat Sep 06 '18 at 09:09
  • 3
    This here is the best answer to the question. – montrealist Oct 25 '19 at 19:01
  • 1
    This should be marked as accepted answer. The question was how to process the form in nodejs not in expressjs. – webduvet Aug 05 '20 at 22:00
  • 1
    Very well written answer! Should be marked as the accepted answer. – Jangita Oct 18 '20 at 05:55
156

Make sure to kill the connection if someone tries to flood your RAM!

var qs = require('querystring');

function (request, response) {
    if (request.method == 'POST') {
        var body = '';
        request.on('data', function (data) {
            body += data;
            // 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
            if (body.length > 1e6) { 
                // FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
                request.connection.destroy();
            }
        });
        request.on('end', function () {

            var POST = qs.parse(body);
            // use POST

        });
    }
}
andlrc
  • 41,466
  • 13
  • 82
  • 108
thejh
  • 41,293
  • 15
  • 89
  • 105
108

Here's a very simple no-framework wrapper based on the other answers and articles posted in here:

var http = require('http');
var querystring = require('querystring');

function processPost(request, response, callback) {
    var queryData = "";
    if(typeof callback !== 'function') return null;

    if(request.method == 'POST') {
        request.on('data', function(data) {
            queryData += data;
            if(queryData.length > 1e6) {
                queryData = "";
                response.writeHead(413, {'Content-Type': 'text/plain'}).end();
                request.connection.destroy();
            }
        });

        request.on('end', function() {
            request.post = querystring.parse(queryData);
            callback();
        });

    } else {
        response.writeHead(405, {'Content-Type': 'text/plain'});
        response.end();
    }
}

Usage example:

http.createServer(function(request, response) {
    if(request.method == 'POST') {
        processPost(request, response, function() {
            console.log(request.post);
            // Use request.post here

            response.writeHead(200, "OK", {'Content-Type': 'text/plain'});
            response.end();
        });
    } else {
        response.writeHead(200, "OK", {'Content-Type': 'text/plain'});
        response.end();
    }

}).listen(8000);
Mahn
  • 14,870
  • 12
  • 57
  • 77
  • 1
    Shouldn't this check be moved to a separate middleware so that it can check for too large requests on all post/put requests – Pavel Nikolov Feb 23 '13 at 12:17
  • 1
    @PavelNikolov this is meant mostly for the quick and dirty jobs, otherwise one is probably better off using Express like the accepted answer here recommends (which probably takes care of managing large requests as well). Feel free to modify and "fork" it to your liking though. – Mahn Feb 23 '13 at 13:24
  • What about the .read() method? Is that not supported by the http module? Eg. response.read() – B T Jul 12 '13 at 23:54
  • Hey, just curious - why have you placed the payload into the response object (response.post) rather than request object? – Jotham Apr 03 '14 at 04:48
  • @Jotham good question... I have no idea why didn't I notice that earlier, but there's no reason why it should be `response.post` rather than the more logical `request.post`. I updated the post. – Mahn Apr 03 '14 at 08:48
  • I am not getting "data" events, only "readable" events, and nothing when I try to request.read(). Using a form similar to the one above. – Elisabeth May 22 '15 at 18:16
90

It will be cleaner if you encode your data to JSON, then send it to Node.js.

function (req, res) {
    if (req.method == 'POST') {
        var jsonString = '';

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

        req.on('end', function () {
            console.log(JSON.parse(jsonString));
        });
    }
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Lewis
  • 11,912
  • 9
  • 59
  • 79
  • 2
    This is what worked for me. Turns out the other solutions returned a string that *looked* like JSON but wasn't parsed. Instead of `qs.parse()`, `JSON.parse()` turned the body into something usable. Example: `var post = JSON.parse(body);`, then access the data with `post.fieldname`. (Moral of the story, if you're confused about what you're seeing, don't forget about `typeof`!) – wmassingham Mar 20 '15 at 00:19
  • 15
    Well just be aware that you must try-catch the JSON.parse function because if i want to crash your application ill just send a body with raw text. – ecarrizo Sep 14 '15 at 05:44
  • You should use `request.setEncoding` to make this work properly else it might not handle non ascii characters properly. – Farid Nouri Neshat Nov 20 '17 at 07:46
  • that really helped – Saeedeh Jun 22 '20 at 08:16
38

For anyone wondering how to do this trivial task without installing a web framework I managed to plop this together. Hardly production ready but it seems to work.

function handler(req, res) {
    var POST = {};
    if (req.method == 'POST') {
        req.on('data', function(data) {
            data = data.toString();
            data = data.split('&');
            for (var i = 0; i < data.length; i++) {
                var _data = data[i].split("=");
                POST[_data[0]] = _data[1];
            }
            console.log(POST);
        })
    }
}
crafter
  • 5,878
  • 1
  • 31
  • 42
Shawn Whinnery
  • 3,069
  • 3
  • 13
  • 16
  • Finally a FULL WORKING solution for this weird problem..also the previous answer helped a lot to understand why there was not any data inside the request when the callback starts.. Many thanks! – luis-br May 18 '17 at 20:17
  • 3
    1) This answer assumes the data are a string. Bad assumption, in a general case. 2) This answer assumes that data arrive in one chunk. Otherwise, splitting by '=' will give unpredictable result. Bad assumption, in a general case. – Konstantin Jun 16 '17 at 17:24
  • @Konstantin Actually this answer assumes the data is a Buffer. Check this out. https://stackoverflow.com/questions/14551194/how-are-parameters-sent-in-an-http-post-request Also this. https://millermedeiros.github.io/mdoc/examples/node_api/doc/streams.html#Event – Shawn Whinnery Jul 12 '17 at 02:54
21

You can use body-parser, the Node.js body parsing middleware.

First load body-parser

$ npm install body-parser --save

Some example code

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

var app = express()

app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())


app.use(function (req, res) {
  var post_data = req.body;
  console.log(post_data);
})

More documentation can be found here

Kirby
  • 13,024
  • 6
  • 79
  • 95
sourcecode
  • 3,210
  • 1
  • 15
  • 12
10

Reference: https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/

let body = [];
request.on('data', (chunk) => {
  body.push(chunk);
}).on('end', () => {
  body = Buffer.concat(body).toString();
  // at this point, `body` has the entire request body stored in it as a string
});
Udhaya
  • 3,749
  • 2
  • 22
  • 36
9

Here is how you can do it if you use node-formidable:

var formidable = require("formidable");

var form = new formidable.IncomingForm();
form.parse(request, function (err, fields) {
    console.log(fields.parameter1);
    console.log(fields.parameter2);
    // ...
});
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Dmitry Efimenko
  • 10,224
  • 7
  • 60
  • 73
  • I am having an issue with the path, when I try to use the path or the path + name to access the file with lwip.open(path or path + name I am getting an error as unobtained image. – Lion789 Mar 12 '16 at 09:18
7

1) Install 'body-parser' from npm.

2) Then in your app.ts

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

3) then you need to write

app.use(bodyParser.json())

in app.ts module

4) keep in mind that you include

app.use(bodyParser.json())

in the top or before any module declaration.

Ex:

app.use(bodyParser.json())
app.use('/user',user);

5) Then use

var postdata = req.body;
Sunil Garg
  • 10,122
  • 12
  • 92
  • 133
7

If you prefer to use pure Node.js then you might extract POST data like it is shown below:

// Dependencies
const StringDecoder = require('string_decoder').StringDecoder;
const http = require('http');

// Instantiate the HTTP server.
const httpServer = http.createServer((request, response) => {
  // Get the payload, if any.
  const decoder = new StringDecoder('utf-8');
  let payload = '';

  request.on('data', (data) => {
    payload += decoder.write(data);
  });

  request.on('end', () => {
    payload += decoder.end();

    // Parse payload to object.
    payload = JSON.parse(payload);

    // Do smoething with the payload....
  });
};

// Start the HTTP server.
const port = 3000;
httpServer.listen(port, () => {
  console.log(`The server is listening on port ${port}`);
});
Oleksii Trekhleb
  • 1,795
  • 16
  • 21
5

If you don't want to chunk your data together with the data callback you can always use the readable callback like this:

// Read Body when Available
request.on("readable", function(){
  request.body = '';
  while (null !== (request.body += request.read())){}
});

// Do something with it
request.on("end", function(){
  request.body //-> POST Parameters as String
});

This approach modifies the incoming request, but as soon as you finish your response the request will be garbage collected, so that should not be a problem.

An advanced approach would be to check the body size first, if you're afraid of huge bodies.

Thomas Fankhauser
  • 4,761
  • 1
  • 27
  • 31
  • Convenient way to do it, but how do you "check the body size first" in a way that can't be fooled by a malicious request? – doug65536 Dec 11 '13 at 02:32
  • `request` is a normal node.js stream, so you can check the `request.headers` for the body length and abort the request if necessary. – Thomas Fankhauser Dec 11 '13 at 10:43
  • 1
    @ThomasFankhauser The body length in the header may not be the correct value or even present. The right way to do it, is as the body arrives and you are buffering it, you check the size to make sure it doesn't pass the limit. – Farid Nouri Neshat Aug 11 '17 at 11:38
4

There are multiple ways to do it. However, the quickest way I know is to use the Express.js library with body-parser.

var express = require("express");
var bodyParser = require("body-parser");
var app = express();

app.use(bodyParser.urlencoded({extended : true}));

app.post("/pathpostdataissentto", function(request, response) {
  console.log(request.body);
  //Or
  console.log(request.body.fieldName);
});

app.listen(8080);

That can work for strings, but I would change bodyParser.urlencoded to bodyParser.json instead if the POST data contains a JSON array.

More info: http://www.kompulsa.com/how-to-accept-and-parse-post-requests-in-node-js/

nikodean2
  • 81
  • 7
4

You need to receive the POST data in chunks using request.on('data', function(chunk) {...})

const http = require('http');

http.createServer((req, res) => {
    if (req.method == 'POST') {
        whole = ''
        req.on('data', (chunk) => {
            # consider adding size limit here
            whole += chunk.toString()
        })

        req.on('end', () => {
            console.log(whole)
            res.writeHead(200, 'OK', {'Content-Type': 'text/html'})
            res.end('Data received.')
        })
    }
}).listen(8080)

You should consider adding a size limit at the indicated position as thejh suggested.

Community
  • 1
  • 1
Zaz
  • 39,637
  • 10
  • 70
  • 92
  • Is this, more, susceptible to a slow-loris attack? –  Jun 08 '17 at 04:19
  • Nodejs is less susceptible to slow-loris than, e.g., php - because it doesn't build a large session object around every http connection. However, it appears this code still could introduce a slow-loris vulnerability. This could be prevented with a `setTimeout` that ends the connection after a certain period of time, if the full request is not received within that window. – Gershy Sep 25 '17 at 18:15
4

Express v4.17.0

app.use(express.urlencoded( {extended: true} ))

console.log(req.body) // object

Demo Form

Another Answer Related

antelove
  • 2,039
  • 16
  • 14
3

If you are using Express.js, before you can access to the req.body, you must add middleware bodyParser:

app.use(express.bodyParser());

Then you can ask for

req.body.user
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
PatricioS
  • 61
  • 4
  • Most middleware (like bodyParser) is no longer bundled with Express and must be installed separately. See the answer from @nikodean2 above for a more current answer – Jeff Collier Feb 26 '16 at 04:12
  • app.use(bodyParser()); works but is giving me deprecation red error messages – Chris Allinson Nov 19 '16 at 23:20
2

And if you don't want to use the entire framework like Express, but you also need different kinds of forms, including uploads, then formaline may be a good choice.

It is listed in Node.js modules

Pavel Koryagin
  • 1,449
  • 11
  • 25
1

you can extract post parameter without using express.

1: nmp install multiparty

2: import multiparty . as var multiparty = require('multiparty');

3: `

if(req.method ==='POST'){
   var form = new multiparty.Form();
   form.parse(req, function(err, fields, files) {
      console.log(fields['userfile1'][0]);
    });
    }

4: and HTML FORM IS .

<form method=POST enctype=multipart/form-data>
<input type=text name=userfile1><br>
<input type=submit>
</form>

I hope this will work for you. Thanks.

Maneesh Singh
  • 517
  • 2
  • 11
1

I found a video which explains on how to achieve this: https://www.youtube.com/watch?v=nuw48-u3Yrg

It uses default "http" module together with "querystring" and "stringbuilder" modules. The application takes two numbers (using two textboxes) from a web page and upon submit, returns sum of those two (along with persisting the values in the textboxes). This is the best example I could find anywhere else.

Related source code:

var http = require("http");
var qs = require("querystring");
var StringBuilder = require("stringbuilder");

var port = 9000;

function getCalcHtml(req, resp, data) {
    var sb = new StringBuilder({ newline: "\r\n" });
    sb.appendLine("<html>");
    sb.appendLine(" <body>");
    sb.appendLine("     <form method='post'>");
    sb.appendLine("         <table>");
    sb.appendLine("             <tr>");
    sb.appendLine("                 <td>Enter First No: </td>");

    if (data && data.txtFirstNo) {
        sb.appendLine("                 <td><input type='text' id='txtFirstNo' name='txtFirstNo' value='{0}'/></td>", data.txtFirstNo);
    }
    else {
        sb.appendLine("                 <td><input type='text' id='txtFirstNo' name='txtFirstNo' /></td>");
    }

    sb.appendLine("             </tr>");
    sb.appendLine("             <tr>");
    sb.appendLine("                 <td>Enter Second No: </td>");

    if (data && data.txtSecondNo) {
        sb.appendLine("                 <td><input type='text' id='txtSecondNo' name='txtSecondNo' value='{0}'/></td>", data.txtSecondNo);
    }
    else {
        sb.appendLine("                 <td><input type='text' id='txtSecondNo' name='txtSecondNo' /></td>");
    }

    sb.appendLine("             </tr>");
    sb.appendLine("             <tr>");
    sb.appendLine("                 <td><input type='submit' value='Calculate' /></td>");
    sb.appendLine("             </tr>");

    if (data && data.txtFirstNo && data.txtSecondNo) {
        var sum = parseInt(data.txtFirstNo) + parseInt(data.txtSecondNo);
        sb.appendLine("             <tr>");
        sb.appendLine("                 <td>Sum: {0}</td>", sum);
        sb.appendLine("             </tr>");
    }

    sb.appendLine("         </table>");
    sb.appendLine("     </form>")
    sb.appendLine(" </body>");
    sb.appendLine("</html>");
    sb.build(function (err, result) {
        resp.write(result);
        resp.end();
    });
}

function getCalcForm(req, resp, data) {
    resp.writeHead(200, { "Content-Type": "text/html" });
    getCalcHtml(req, resp, data);
}

function getHome(req, resp) {
    resp.writeHead(200, { "Content-Type": "text/html" });
    resp.write("<html><html><head><title>Home</title></head><body>Want to some calculation? Click <a href='/calc'>here</a></body></html>");
    resp.end();
}

function get404(req, resp) {
    resp.writeHead(404, "Resource Not Found", { "Content-Type": "text/html" });
    resp.write("<html><html><head><title>404</title></head><body>404: Resource not found. Go to <a href='/'>Home</a></body></html>");
    resp.end();
}

function get405(req, resp) {
    resp.writeHead(405, "Method not supported", { "Content-Type": "text/html" });
    resp.write("<html><html><head><title>405</title></head><body>405: Method not supported</body></html>");
    resp.end();
}

http.createServer(function (req, resp) {
    switch (req.method) {
        case "GET":
            if (req.url === "/") {
                getHome(req, resp);
            }
            else if (req.url === "/calc") {
                getCalcForm(req, resp);
            }
            else {
                get404(req, resp);
            }
            break;
        case "POST":
            if (req.url === "/calc") {
                var reqBody = '';
                req.on('data', function (data) {
                    reqBody += data;
                    if (reqBody.length > 1e7) { //10MB
                        resp.writeHead(413, 'Request Entity Too Large', { 'Content-Type': 'text/html' });
                        resp.end('<!doctype html><html><head><title>413</title></head><body>413: Request Entity Too Large</body></html>');
                    }
                });
                req.on('end', function () {
                    var formData = qs.parse(reqBody);
                    getCalcForm(req, resp, formData);
                });
            }
            else {
                get404(req, resp);
            }
            break;
        default:
            get405(req, resp);
            break;
    }
}).listen(port);
user203687
  • 6,223
  • 10
  • 46
  • 78
1

On form fields like these

   <input type="text" name="user[name]" value="MyName">
   <input type="text" name="user[email]" value="myemail@somewherefarfar.com">

some of the above answers will fail because they only support flat data.

For now I am using the Casey Chu answer but with the "qs" instead of the "querystring" module. This is the module "body-parser" uses as well. So if you want nested data you have to install qs.

npm install qs --save

Then replace the first line like:

//var qs = require('querystring');
var qs = require('qs'); 

function (request, response) {
    if (request.method == 'POST') {
        var body = '';

        request.on('data', function (data) {
            body += data;

            // Too much POST data, kill the connection!
            // 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
            if (body.length > 1e6)
                request.connection.destroy();
        });

        request.on('end', function () {
            var post = qs.parse(body);
            console.log(post.user.name); // should work
            // use post['blah'], etc.
        });
    }
}
Geza Turi
  • 74
  • 3
  • 9
1

For those using raw binary POST upload without encoding overhead you can use:

client:

var xhr = new XMLHttpRequest();
xhr.open("POST", "/api/upload", true);
var blob = new Uint8Array([65,72,79,74]); // or e.g. recorder.getBlob()
xhr.send(blob);

server:

var express = require('express');
var router = express.Router();
var fs = require('fs');

router.use (function(req, res, next) {
  var data='';
  req.setEncoding('binary');
  req.on('data', function(chunk) {
    data += chunk;
  });

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

router.post('/api/upload', function(req, res, next) {
  fs.writeFile("binaryFile.png", req.body, 'binary', function(err) {
    res.send("Binary POST successful!");
  });
});
lukyer
  • 6,141
  • 1
  • 31
  • 28
1

You can use the express middleware, which now has body-parser built into it. This means all you need to do is the following:

import express from 'express'

const app = express()

app.use(express.json())

app.post('/thing', (req, res) => {
  console.log(req.body) // <-- this will access the body of the post
  res.sendStatus(200)
})

That code example is ES6 with Express 4.16.x

Big Money
  • 6,272
  • 5
  • 20
  • 32
0

Limit POST size avoid flood your node app. There is a great raw-body module, suitable both for express and connect, that can help you limit request by size and length.

EricSonaron
  • 4,400
  • 3
  • 29
  • 38
0

If it involves a file upload, the browser usually send it as a "multipart/form-data" content-type. You can use this in such cases

var multipart = require('multipart');
multipart.parse(req)

Reference 1

Reference 2

Community
  • 1
  • 1
user3526
  • 1,180
  • 1
  • 15
  • 25
0

You can easily send and get the response of POST request by using "Request - Simplified HTTP client" and Javascript Promise.

var request = require('request');

function getData() {
    var options = {
        url: 'https://example.com',
        headers: {
            'Content-Type': 'application/json'
        }
    };

    return new Promise(function (resolve, reject) {
        var responseData;
        var req = request.post(options, (err, res, body) => {
            if (err) {
                console.log(err);
                reject(err);
            } else {
                console.log("Responce Data", JSON.parse(body));
                responseData = body;
                resolve(responseData);
            }
        });
    });
}
0

You need to use bodyParser() if you want the form data to be available in req.body. body-parser parses your request and converts it into a format from which you can easily extract relevant information that you may need.

For example, let’s say you have a sign-up form at your frontend. You are filling it, and requesting server to save the details somewhere.

Extracting username and password from your request goes as simple as below if you use body-parser.

…………………………………………………….

var loginDetails = {

username : request.body.username,

password : request.body.password

};
Rubin bhandari
  • 1,321
  • 10
  • 16
0

if you receive the data from POST in JSON. :

  import http from 'http';
  const hostname  = '127.0.0.1'; 
  const port = 3000;

  const httpServer:  http.Server = http.createServer((req: http.IncomingMessage, res: 
         http.ServerResponse) => {

        if(req.method === 'POST') {
        let body: string = ''; 
          req.on('data',(chunck) => {
            body += chunck;
          });

          req.on('end', () => {
            const body = JSON.parse(body);
            res.statusCode = 200;
            res.end('OK post');
          });
       }
 
     });

     httpServer.listen(port, hostname, () => {
       console.info(`Server started at port ${port}`);
     })
De Bonheur
  • 171
  • 1
  • 9
-1

ONE LINER without MIDDLEWARE
If you post following data,
'name':'ABC'
Then you can parse it using the following one liner,

require('url').parse(req.url, true).query.name
Hardik Trivedi
  • 343
  • 3
  • 9