协慌网

登录 贡献 社区

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

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

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

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

有图书馆还是黑客?

答案

您可以使用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 input字段,则可以使用变量post访问:

console.log(post.age);

如果使用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: "[email protected]"
        }
    })
});

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

这里有很多答案已经不是很好的做法,或者什么也没解释,所以这就是我写这个的原因。

基本

调用 http.createServer 的回调时,是服务器实际上已接收到该请求的所有标头,但是有可能尚未接收到数据,因此我们必须等待。 http 请求对象(一个 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.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)

这里使用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)

解析内容

如果您尝试接受不带文件的 HTML 表单 POST 提交,或者使用默认的内容类型处理 jQuery ajax调用,则该内容类型是使用utf-8编码的application/x-www-form-urlencoded您可以使用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)

限制数据量

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

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

或者

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

或者

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

NPM 模块

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

如果您不使用框架,那么身体会很好。