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

How to process POST data in Node.js?

如何从Node.js中的HTTP POST方法中提取表单数据(form[method="post"])和文件上载?

我已经阅读了文档,谷歌搜索,什么也没找到。

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

有图书馆还是黑客?


您可以使用querystring模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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.
        });
    }
}

现在,例如,如果您有一个名为ageinput字段,则可以使用变量post访问它:

1
console.log(post.age);


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

HTML:

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

API客户端:

1
2
3
4
5
6
7
8
9
10
11
12
fetch('/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        user: {
            name:"John",
            email:"[email protected]"
        }
    })
});

Node.js :(自Express v4.16.0起)

1
2
3
4
5
6
7
8
9
10
11
// 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 :(对于Express <4.16.0)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)
});


如果有人试图淹没你的内存,请确保终止连接!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

        });
    }
}


这是一个非常简单的无框架包装器,基于其他答案和文章发布在这里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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();
    }
}

用法示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);


这里的很多答案不再是好的做法,也不会解释任何事情,所以这就是我写这篇文章的原因。

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

1
2
3
4
5
6
7
8
9
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)

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

现在你可能对它自己的每个块都不感兴趣,所以在这种情况下你可能希望像这样缓冲它:

1
2
3
4
5
6
7
8
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)

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

1
2
3
4
5
6
7
const http = require('http');
const concat = require('concat-stream');
http.createServer((request, response) => {
  concat(request, data => {
    console.log('Data: ', data);
  });
}).listen(8080)

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

1
2
3
4
5
6
7
8
9
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)

如果你的内容类型是JSON,你可以简单地使用JSON.parse而不是qs.parse。

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

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

因此,如果要将内容保存到文件:

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

正如其他答案所指出的那样,请记住,恶意客户端可能会向您发送大量数据以使您的应用程序崩溃或填满您的内存以便保护,以确保您丢弃发出数据的请求超过某个限制。如果您不使用库来处理传入的数据。我建议使用像流量计这样的东西,如果达到指定的限制可以中止请求:

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

要么

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

要么

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

还尝试使用npm模块而不是自己实现,因为它们可能会更好地处理边缘情况。对于表达我建议使用body-parser。对于koa,有一个类似的模块。

如果你不使用框架,身体是相当不错的。


如果您将数据编码为JSON,然后将其发送到Node.js.将更清洁。

1
2
3
4
5
6
7
8
9
10
11
12
13
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));
        });
    }
}


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
        })
    }
}


您可以使用body-parser,Node.js正文解析中间件。

首先加载body-parser

1
$ npm install body-parser --save

一些示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
})

可在此处找到更多文档


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

1
2
3
4
5
6
7
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
});


如果使用node-formidable,可以使用以下命令:

1
2
3
4
5
6
7
8
var formidable = require("formidable");

var form = new formidable.IncomingForm();
form.parse(request, function (err, fields) {
    console.log(fields.parameter1);
    console.log(fields.parameter2);
    // ...
});


如果您更喜欢使用纯Node.js,那么您可能会提取POST数据,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 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}`);
});


1)从npm安装'body-parser'

2)然后在你的app.ts

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

3)然后你需要写

1
app.use(bodyParser.json())

在app.ts模块中

4)请记住,你包括

1
app.use(bodyParser.json())

在顶部或任何模块声明之前。

例如:

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

5)然后使用

1
var postdata = req.body;

如果您不想将数据与data回调一起分块,则可以始终使用readable回调,如下所示:

1
2
3
4
5
6
7
8
9
10
// 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
});

此方法修改传入的请求,但是一旦您完成响应,请求将被垃圾收集,因此这不应该是一个问题。

如果你害怕巨大的身体,一个先进的方法是首先检查身体大小。


有多种方法可以做到这一点。但是,我知道最快的方法是将Express.js库与body-parser一起使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
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);

这可以用于字符串,但如果POST数据包含JSON数组,我会将bodyParser.urlencoded更改为bodyParser.json。

更多信息:http://www.kompulsa.com/how-to-accept-and-parse-post-requests-in-node-js/


您需要使用request.on('data', function(chunk) {...})以块的形式接收POST数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)

您应该考虑在指示位置添加大小限制,如建议的那样。


如果您使用Express.js,在访问req.body之前,必须添加中间件bodyParser:

1
app.use(express.bodyParser());

然后你可以要求

1
req.body.user


如果您不想使用像Express这样的整个框架,但是您还需要不同类型的表单,包括上传,那么福尔马林可能是一个不错的选择。

它列在Node.js模块中


我找到了一个视频,解释了如何实现这个目标:

它使用默认的"http"模块以及"querystring"和"stringbuilder"模块。应用程序从网页中获取两个数字(使用两个文本框),并在提交时返回这两个数字的总和(以及保留文本框中的值)。这是我在其他地方找到的最好的例子。

相关源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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:"

" });
    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>Home</head><body>Want to some calculation? Click here</body></html>");
    resp.end();
}

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

function get405(req, resp) {
    resp.writeHead(405,"Method not supported", {"Content-Type":"text/html" });
    resp.write("<html><html><head>405</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>413</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);

对于使用原始二进制POST上传而没有编码开销的用户,可以使用:

客户:

1
2
3
4
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);

服务器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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!");
  });
});


您可以使用快速中间件,它现在内置了主体解析器。这意味着您需要做的就是以下内容:

1
2
3
4
5
6
7
8
9
10
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)
})

该代码示例是带有Express 4.16.x的ES6


限制POST大小避免泛滥您的节点应用程序。
有一个很棒的原始模块,适用于快速和连接,可以帮助您按大小和长度限制请求。


如果希望表单数据在req.body中可用,则需要使用bodyParser()。
body-parser解析您的请求并将其转换为一种格式,您可以从中轻松提取您可能需要的相关信息。

例如,假设您的前端有一个注册表单。 您正在填写它,并请求服务器在某处保存详细信息。

如果您使用正文解析器,从您的请求中提取用户名和密码就像下面一样简单。

............................................................。

1
2
3
4
5
6
7
var loginDetails = {

username : request.body.username,

password : request.body.password

};

如果涉及文件上传,则浏览器通常将其作为"multipart/form-data"内容类型发送。
在这种情况下你可以使用它

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

参考1

参考2


在这些表单字段上

1
2
   <input type="text" name="user[name]" value="MyName">
   <input type="text" name="user[email]" value="[email protected]">

上述一些答案将失败,因为它们只支持平面数据。

现在我使用Casey Chu的答案,但使用"qs"而不是"querystring"模块。这是模块"body-parser"也使用。因此,如果您想要嵌套数据,则必须安装qs。

1
npm install qs --save

然后替换第一行,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//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.
        });
    }
}


您可以使用"请求 - 简化的HTTP客户端"和Javascript承诺轻松发送和获取POST请求的响应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
            }
        });
    });
}

你可以不使用快递提取post参数。

1:nmp install multiparty

2:导入多方。如var multiparty = require('multiparty');

3:`

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

4:和HTML FORM IS。

1
2
3
4
<form method=POST enctype=multipart/form-data>
<input type=text name=userfile1>
<input type=submit>
</form>

我希望这对你有用。谢谢。