如何在 Node.js 中处理 POST 数据?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4295782/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 13:44:19  来源:igfitidea点击:

How to process POST data in Node.js?

node.jshttp-post

提问by Ming-Tang

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

你如何在Node.js 中提取form[method="post"]从 HTTPPOST方法发送的表单数据 ( ) 和文件上传?

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

我已经阅读了文档,用谷歌搜索并没有发现任何东西。

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

Is there a library or a hack?

有图书馆或黑客吗?

采纳答案by Baggz

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

如果您使用Express(用于 Node.js 的高性能、高级 Web 开发),您可以这样做:

HTML:

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:

API客户端:

fetch('/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        user: {
            name: "John",
            email: "[email protected]"
        }
    })
});

Node.js:(since Express v4.16.0)

Node.js:(自 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)

Node.js:(对于 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)
});

回答by Casey Chu

You can use the querystringmodule:

您可以使用该querystring模块:

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 inputfield with name age, you could access it using the variable post:

现在,例如,如果您有一个input名为 name的字段age,您可以使用变量访问它post

console.log(post.age);

回答by thejh

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

如果有人试图淹没您的 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

        });
    }
}

回答by Farid Nouri Neshat

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 readablestream. In readable streams whenever a chunk of data arrives, a dataevent is emitted(assuming you have registered a callback to it) and when all chunks have arrived an endevent is emitted. Here's an example on how you listen to the events:

当调用 http.createServer 的回调时,是服务器实际收到了请求的所有头,但可能还没有收到数据,所以我们必须等待它。该http请求对象(http.IncomingMessage实例)实际上是一个可读。在可读流中,每当数据块到达时,就会发出一个事件(假设您已经向它注册了回调),并且当所有数据块都到达时,会发出一个事件。以下是有关如何侦听事件的示例:dataend

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.setEncodingmethod which causes the stream emit strings interpreted with the given encoding and handles multi-byte characters properly.

如果您尝试这样做,您会注意到块是缓冲区。如果您不处理二进制数据并且需要使用字符串,我建议使用request.setEncoding方法,它会导致流发出用给定编码解释的字符串并正确处理多字节字符。

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.concatis used, which simply concatenates all buffers and return one big buffer. You can also use the concat-stream modulewhich does the same:

这里使用了Buffer.concat,它简单地连接所有缓冲区并返回一个大缓冲区。您还可以使用执行相同操作的concat-stream 模块

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 ajaxcalls with the default content type, then the content type is application/x-www-form-urlencodedwith uft-8encoding. You can use the querystring moduleto de-serialize it and access the properties:

如果您尝试接受没有文件的 HTML 表单 POST 提交或使用默认内容类型处理jQuery ajax调用,则内容类型是application/x-www-form-urlencoded带有uft-8编码的。您可以使用querystring 模块反序列化它并访问属性:

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.parseinstead of qs.parse.

如果您的内容类型是 JSON,则可以简单地使用JSON.parse而不是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 answerof mine where I have posted helpful links and modules for multipart content.

如果您正在处理文件或处理多部分内容类型,那么在这种情况下,您应该使用类似 formidable 之类的东西来消除处理它的所有痛苦。看看我的另一个答案,我在其中发布了多部分内容的有用链接和模块。

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 itrather than buffering it, as it'll be less code, handles back pressure better, it'll take less memory and in some cases faster.

如果您不想解析内容而是将其传递到其他地方,例如将其作为数据发送到另一个 http 请求或将其保存到文件中,我建议对其进行管道传输而不是缓冲它,因为它会更少代码,更好地处理背压,它会占用更少的内存,在某些情况下更快。

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-meterwhich can abort the request if reaches the specified limit:

正如其他答案所指出的那样,请记住,恶意客户端可能会向您发送大量数据以使您的应用程序崩溃或填满您的内存,以确保您删除发出数据的请求超过特定限制。如果您不使用库来处理传入的数据。我建议使用类似stream-meter 的东西,如果达到指定的限制,它可以中止请求:

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

NPM 模块

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.

虽然我在上面描述了如何使用 HTTP 请求正文来简单地缓冲和解析内容,但我建议使用这些模块之一而不是自己实现,因为它们可能会更好地处理边缘情况。对于 express 我建议使用body-parser。对于 koa,有一个类似的模块

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

如果不使用框架,body是相当不错的。

回答by Mahn

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

回答by Lewis

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

如果您将数据编码为JSON,然后将其发送到 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));
        });
    }
}

回答by Shawn Whinnery

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.

对于想知道如何在不安装 Web 框架的情况下完成这项微不足道的任务的任何人,我设法将其放在一起。几乎没有准备好生产,但它似乎工作。

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

回答by sourcecode

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

您可以使用body-parserNode.js 主体解析中间件。

First load body-parser

第一次加载 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

可以在此处找到更多文档

回答by Udhaya

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

参考: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
});

回答by Dmitry Efimenko

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

如果您使用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);
    // ...
});