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

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

我读了留档,谷歌搜索,一无所获。

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

有图书馆或黑客吗?

1223921 次浏览

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

超文本标记语言:

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

客户端接口:

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

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:(用于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)
});

您可以使用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.
});
}
}

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

console.log(post.age);

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

它被列入Node.js模块

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


});
}
}

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

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

使用示例:

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

如果您不想将数据与data回调组合在一起,您可以随时使用readable回调,如下所示:

// 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,在访问req.body之前,您必须添加中间件身体分析器:

app.use(express.bodyParser());

然后你可以要求

req.body.user

以下是使用节点强大时如何做到这一点:

var formidable = require("formidable");


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

如果你将您的数据编码为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));
});
}
}

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

首次加载body-parser

$ npm install body-parser --save

一些示例代码

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

更多留档可以找到这里

如果有人想知道如何在不安装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);
})
}
}

您可以在不使用Express的情况下提取post参数。

1:nmp install multiparty

2:导入多方。作为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:超文本标记语言FORM IS。

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

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

限制POST大小避免淹没您的节点应用程序。 有一个很棒的未处理主体模块,适用于快速和连接,可以帮助您根据大小和长度限制请求。

我找到了一个视频,解释了如何实现这一点: https://www.youtube.com/watch?v=nuw48-u3Yrg

它使用默认的“超文本传输协议”模块以及“querystring”和“stringBuilder”模块。该应用程序从网页中获取两个数字(使用两个文本框),并在提交时返回这两个数字的总和(以及将值持久化在文本框中)。这是我在其他任何地方都能找到的最好的例子。

相关源代码:

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

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

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

参考文献1

参考文献2

有多种方法可以做到这一点。然而,我知道的最快的方法是使用带有身体解析器的Express.js库。

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/

在像这样的表单字段上

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

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

目前,我使用凯西·朱的答案,但使用"qs"而不是“查询字符串”模块。这也是身体解析器使用的模块。所以如果你想要嵌套数据,你必须安装qs。

npm install qs --save

然后将第一行替换为:

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

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

客户端:

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

服务端:

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

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

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)

您应该考虑在指定位置添加大小限制thejh建议

这里的很多答案不再是好的实践,或者没有解释任何事情,所以这就是我写这篇文章的原因。

基础

调用http.createServer的回调时,是服务器实际上已经收到请求的所有标头,但有可能还没有收到数据,所以我们必须等待它。超文本传输协议请求对象(http. IncomingMessage实例)实际上是一个可读。在可读流中,每当数据块到达时,一个data事件被发出(假设你已经注册了一个回调),当所有数据块到达时,就会发出一个end事件。这是一个如何监听事件的示例:

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.set编码方法,该方法会导致流发出使用给定编码解释的字符串并正确处理多字节字符。

缓冲块

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

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,它简单地连接所有缓冲区并返回一个大缓冲区。您也可以使用流模块执行相同的操作:

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

解析内容

如果您尝试接受无文件的超文本标记语言表单POST提交或使用默认内容类型处理jQuery ajax调用,则内容类型为application/x-www-form-urlencodedutf-8编码。您可以使用查询串模块对其进行反序列化并访问属性:

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.createServer((request, response) => {
request.pipe(fs.createWriteStream('./request'));
}).listen(8080)

限制数据量

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

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

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

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

NPM模块

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

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

1)从npm安装'body-parser'

2)然后在你的app.ts

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

(3)你需要写

app.use(bodyParser.json())

app.ts模块中

4)请记住,您包括

app.use(bodyParser.json())

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

例如:

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

5)然后使用

var postdata = req.body;

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

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

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

您可以使用表达中间件,它现在内置了身体解析器。这意味着您需要做的就是以下操作:

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

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

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

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

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

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

………………………………………………

var loginDetails = {


username : request.body.username,


password : request.body.password


};

Express v4.17.0

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


console.log(req.body) // object

演示表

相关答案

如果您收到来自POST的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}`);
})

详细说明如何使用URLSearchParams

const http = require('http');


const POST_HTML =
'<html><head><title>Post Example</title></head>' +
'<body>' +
'<form method="post">' +
'Input 1: <input name="input1"><br>' +
'Input 2: <input name="input2"><br>' +
'Input 1: <input name="input1"><br>' +
'<input type="submit">' +
'</form>' +
'</body></html>';


const FORM_DATA = 'application/x-www-form-urlencoded';


function processFormData(body) {
const params = new URLSearchParams(body);


for ([name, value] of params.entries()) console.log(`${name}: ${value}`);
}


// req: http.IncomingMessage
// res: http.ServerResponse
//
function requestListener(req, res) {
const contentType = req.headers['content-type'];
let body = '';


const append = (chunk) => {
body += chunk;
};
const complete = () => {
if (contentType === FORM_DATA) processFormData(body);


res.writeHead(200);
res.end(POST_HTML);
};


req.on('data', append);
req.on('end', complete);
}


http.createServer(requestListener).listen(8080);
$ node index.js
input1: one
input2: two
input1: three

以现代异步方式Node.js18,具有零依赖关系:

server.mjs:

import { createServer } from 'node:http';


const rawReqToString = async (req) => {
const buffers = [];
for await(const chunk of req){
buffers.push(chunk);
}
return Buffer.concat(buffers).toString();
};


const server = createServer(async (req, res) => {
const object = JSON.parse(await rawReqToString(req));
...
});


server.listen(3000, 'localhost', () => {
console.log(`The server is running.`);
})