Как обрабатывать POST-данные в Node.js? - PullRequest
563 голосов
/ 28 ноября 2010

Как извлечь данные формы (form[method="post"]) и загрузки файлов, отправленные с помощью метода HTTP POST в Node.js ?

Я прочитал документацию, гуглил и ничего не нашел.

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

Есть библиотека или взлом?

Ответы [ 26 ]

678 голосов
/ 30 ноября 2010

Вы можете использовать модуль 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.
        });
    }
}

Теперь, например, если у вас есть поле input с именем age, вы можете получить к нему доступ с помощью переменной post:

console.log(post.age);
497 голосов
/ 28 ноября 2010

Если вы используете Express (высокопроизводительная высококлассная веб-разработка для Node.js), вы можете сделать следующее:

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) </p>

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)
});
142 голосов
/ 27 декабря 2011

Обязательно разорвите соединение, если кто-то попытается заполнить вашу 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

        });
    }
}
97 голосов
/ 19 августа 2012

Вот очень простая оболочка без фреймворка, основанная на других ответах и ​​статьях, размещенных здесь:

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);
82 голосов
/ 07 января 2017

Многие ответы здесь уже не являются хорошими практиками или ничего не объясняют, поэтому я и пишу это.

Когда вызывается функция обратного вызова 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)

Если вы пытаетесь принять отправку POST HTML-форм без файлов или передаете вызовы jQuery ajax с типом контента по умолчанию, тогда тип контента - application/x-www-form-urlencoded с кодировкой uft-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-запрос в качестве данных или сохранить его в файл, который я предлагаю , отправив по трубопроводу вместо буферизация, так как будет меньше кода, лучше справится с обратным давлением, займет меньше памяти, а в некоторых случаях быстрее.

Итак, если вы хотите сохранить содержимое в файл:

 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, реализовав их самостоятельно, поскольку они, вероятно, будут лучше обрабатывать крайние случаи. Для экспресса я предлагаю использовать body-parser . Для koa существует аналогичный модуль .

Если вы не используете фреймворк, body довольно хорошо.

76 голосов
/ 22 июля 2014

Будет чище, если вы закодируете свои данные в 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));
        });
    }
}
34 голосов
/ 16 октября 2014

Для тех, кто интересуется, как выполнить эту тривиальную задачу без установки веб-фреймворка, мне удалось собрать все вместе.Вряд ли производство готово, но, похоже, работает.

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);
        })
    }
}
11 голосов
/ 09 октября 2014

Вы можете использовать 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);
})

Дополнительную документацию можно найти здесь

9 голосов
/ 24 января 2018

Ссылка: 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
});
7 голосов
/ 21 мая 2014

Вот как вы можете это сделать, если используете 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);
    // ...
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...