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

我看了文件,谷歌了一下,什么都没找到。

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

有图书馆或黑客吗?


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

HTML:

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

API客户端:

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

现在,例如,如果你有一个名为age的输入字段,你可以使用变量post访问它:

console.log(post.age);

如果你不想使用整个框架,如Express,但你也需要不同种类的表单,包括上传,那么formaline可能是一个不错的选择。

它列在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);

如果你不想把数据和数据回调放在一起,你可以像这样使用可读回调:

// 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. js之前。body,你必须添加中间件bodyParser:

app.use(express.bodyParser());

然后你可以要求

req.body.user

如果你使用node- terrible,你可以这样做:

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解析中间件。

第一个负载体解析器

$ 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安装多方

2:导入多方。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:和HTML形式是。

<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

它使用默认的“http”模块以及“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


有很多种方法。然而,我所知道的最快的方法是使用带有body-parser的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);

这可以用于字符串,但我要更改bodyParser。urlencoded to bodyParser。如果POST数据包含json数组,则改为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">

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

现在我正在使用Casey Chu的答案,但使用“qs”而不是“querystring”模块。这也是“体解析器”使用的模块。所以如果你想要嵌套数据,你必须安装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!");
  });
});

您需要使用请求以块的形式接收POST数据。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)

你应该考虑像jh建议的那样在指定位置增加一个尺寸限制。


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

基础知识

When the callback of http.createServer is called, is when the server has actually received all the headers for the request, but it's possible that the data has 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)

将缓冲区转换为字符串

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

缓冲块

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

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)

这里的缓冲区。使用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)

解析内容

如果你试图接受HTML表单POST提交没有文件或处理jQuery ajax调用默认的内容类型,那么内容类型是application/x-www-form-urlencoded utf-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)

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

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

管道

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

所以如果你想保存内容到一个文件:

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

限制数据量

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

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模块

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

如果你不使用框架,body是很好的。


1)从npm安装body-parser。

2)然后在app.ts中

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

3)然后你需要写

app.use(bodyParser.json())

在app.ts模块中

4)记住你要包括

app.use(bodyParser.json())

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

Ex:

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


您可以使用express中间件,该中间件现在内置了体解析器。这意味着你所需要做的就是:

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


您可以使用“request - Simplified HTTP client”和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中可用,则需要使用bodyParser()。 Body-parser解析您的请求并将其转换为可以轻松提取所需相关信息的格式。

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

如果使用体解析器,则从请求中提取用户名和密码如下所示。

.............................................................

var loginDetails = {

username : request.body.username,

password : request.body.password

};

表达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:

Node.js知识:如何读取POST数据? 类:URLSearchParams .js文档 MDN: 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.js 18的现代异步方式,零依赖:

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