如何在 Node.js 中提取 POST 数据?

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?

转载于:https://stackoverflow.com/questions/4295782/how-do-you-extract-post-data-in-node-js

23个回答

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>

JavaScript:

app.use(express.bodyParser());

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

UPDATED on 1/June/2016:

Method above is deprecated use now:

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)
});
csdnceshi68
local-host I didn't came to this question to find answer using Express.js
接近 3 年之前 回复
csdnceshi76
斗士狗 This is amazing. Thank you.
接近 3 年之前 回复
csdnceshi73
喵-见缝插针 Don't follow this answer unless you want a ton of dependencies installed as well. Use this answer instead: stackoverflow.com/a/4310087/4808079
大约 3 年之前 回复
csdnceshi71
Memor.の This answer is outdated and wrong (Express does not include a bodyParser anymore). Casey Chu is the one that posted the correct answer.
大约 5 年之前 回复
csdnceshi65
larry*wei Not useful unless you use express. I'd downvote if I could.
大约 5 年之前 回复
csdnceshi54
hurriedly% This crap again: doxdesk.com/img/updates/20091116-so-large.gif
5 年多之前 回复
csdnceshi69
YaoRaoLov 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?
5 年多之前 回复
csdnceshi59
ℙℕℤℝ 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?
接近 6 年之前 回复
csdnceshi74
7*4 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.
大约 6 年之前 回复
weixin_41568174
from.. 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()).
大约 6 年之前 回复
csdnceshi56
lrony* 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.
6 年多之前 回复
csdnceshi55
~Onlooker how would you receive the raw body value, is it part of the http specification that message bodies must be url parsable?
6 年多之前 回复
csdnceshi77
狐狸.fox app.use(express.bodyParser(); is missing a parenthesis
6 年多之前 回复
csdnceshi61
derek5. bodyParser added to above script.
6 年多之前 回复
csdnceshi79
python小菜 I don't think the question was about express..
6 年多之前 回复
weixin_41568131
10.24 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.
接近 7 年之前 回复
weixin_41568183
零零乙 andrewkelley.me/post/do-not-use-bodyparser-with-express-js.html
接近 7 年之前 回复
csdnceshi67
bug^君 Why is this a valid answer if he/she has not asked about Express?
大约 7 年之前 回复
weixin_41568131
10.24 Could somebody point to the place in Express that handles the RAM flooding vulnerability present in using the plain http module?
大约 7 年之前 回复
csdnceshi52
妄徒之命 This didn't work for me until I added app.use(express.bodyParser());.
7 年多之前 回复
csdnceshi64
游.程 Fixed.
大约 8 年之前 回复
csdnceshi53
Lotus@ God!! am getting mad having to read 3 doumentations at the same time for the same framework :/ nodejs.org/api/http.html , senchalabs.org/connect & expressjs.com/guide.html
大约 8 年之前 回复
weixin_41568110
七度&光 req.body.user == {name: 'some value', email: 'some value'}. It looks like there is a typo above
8 年多之前 回复
csdnceshi62
csdnceshi62 I'm confused. How does name="user[email]" correspond to request.body.email ?
8 年多之前 回复
weixin_41568184
叼花硬汉 The functionality is actually in the BodyParser module in connect, if you want to use a lower level entry point.
9 年多之前 回复

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);
csdnceshi63
elliott.david 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 :-)
大约 2 年之前 回复
csdnceshi62
csdnceshi62 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.
大约 2 年之前 回复
csdnceshi63
elliott.david + 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.
大约 2 年之前 回复
csdnceshi63
elliott.david 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).
大约 2 年之前 回复
csdnceshi62
csdnceshi62 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.
大约 2 年之前 回复
csdnceshi56
lrony* 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.
3 年多之前 回复
csdnceshi54
hurriedly% ah ok maybe you wanna highlight that in your answer :)
接近 4 年之前 回复
csdnceshi69
YaoRaoLov It was a string back in 2010 :)
接近 4 年之前 回复
csdnceshi54
hurriedly% isn't type of data in "data" event handler (of request object) of type Buffer, how come concatenation works?
接近 4 年之前 回复
csdnceshi51
旧行李 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.
4 年多之前 回复
csdnceshi57
perhaps? it's an async callback, the return doesn't do nothing in this situation
4 年多之前 回复
csdnceshi77
狐狸.fox How to handle file field with this scenario? That is <input id="fileupload" type="file" name="files[]" multiple>. 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?
大约 5 年之前 回复
csdnceshi50
三生石@ Easily fixable with return
5 年多之前 回复
csdnceshi59
ℙℕℤℝ 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...
接近 6 年之前 回复
csdnceshi70
笑故挽风 You could also use the readablecallback instead of building the data into a body string. Once it is fired, the body is available through request.read();
7 年多之前 回复
csdnceshi66
必承其重 | 欲带皇冠 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);
7 年多之前 回复
csdnceshi63
elliott.david 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.
7 年多之前 回复
csdnceshi69
YaoRaoLov 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.
8 年多之前 回复
csdnceshi76
斗士狗 bad idea. add some stuff for nuking requests when body becomes too big, or someone can kill node by uploading an endless file.
接近 9 年之前 回复

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

        });
    }
}
csdnceshi58
Didn"t forge Just FYI, some of these ideas were codified in a npm module: npmjs.org/package/parse-post
6 年多之前 回复
csdnceshi50
三生石@ Can someone help, if I post {'Name':'Joe'} I get { {'Name':'Joe'} : '' } after qs.Parse(POST)...
7 年多之前 回复
csdnceshi69
YaoRaoLov var POST = qs.parse(body); // use POST only for noobs: 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);
7 年多之前 回复
csdnceshi65
larry*wei in this case, POST[name] (e.g. POST["foo"]).
7 年多之前 回复
csdnceshi76
斗士狗 where do you define the name of the post? ex: $_POST['????']
7 年多之前 回复
csdnceshi65
larry*wei No, it's 1*10^6=1000000.
7 年多之前 回复
weixin_41568126
乱世@小熊 Thank you for the code sir, does 1e6 equate to "1.0*106"?
7 年多之前 回复
csdnceshi64
游.程 You may also return HTTP 413 Error Code (Request Entity Too Large)
大约 8 年之前 回复

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

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)

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.

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)

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 uft-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.

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)

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)), ...);

Also try to use npm 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.

csdnceshi78
程序go 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.
大约 2 年之前 回复
csdnceshi74
7*4 How does this effect performance when compared to processing a GET request without an 'end' handler, ie without buffering chunks?
大约 2 年之前 回复
weixin_41568208
北城已荒凉 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 :)
3 年多之前 回复
csdnceshi78
程序go I can't tell why without seeing your code. Note that for every request, request.on('end', ...) will be called.
3 年多之前 回复
weixin_41568208
北城已荒凉 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?
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
csdnceshi52
妄徒之命 app.use(bodyParser()); works but is giving me deprecation red error messages
接近 4 年之前 回复
weixin_41568196
撒拉嘿哟木头 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
4 年多之前 回复

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

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.

weixin_41568110
七度&光 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.
大约 3 年之前 回复
csdnceshi72
谁还没个明天 Is this, more, susceptible to a slow-loris attack?
3 年多之前 回复

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

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

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.

csdnceshi64
游.程 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.
大约 3 年之前 回复
csdnceshi75
衫裤跑路 request is a normal node.js stream, so you can check the request.headers for the body length and abort the request if necessary.
接近 7 年之前 回复
weixin_41568208
北城已荒凉 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?
接近 7 年之前 回复
共23条数据 1 3 尾页
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐