Как обрабатывать POST-данные в Node.js?

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

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

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

Есть ли библиотека или хак?

Ответ 1

Если вы используете 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: "[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 & lt; 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)
});

Ответ 2

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

Ответ 3

Убедитесь, что вы убили соединение, если кто-то пытается затопить вашу оперативную память!

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

        });
    }
}

Ответ 4

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

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

Ответ 5

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

Когда вызывается обратный вызов http.createServer, это когда сервер действительно получил все заголовки для запроса, но возможно, что данные еще не получены, поэтому мы должны ждать его. объект запроса HTTP (экземпляр http.IncomingMessage) на самом деле является readable stream. В читаемых потоках всякий раз, когда приходит кусок данных, событие 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 module, который делает то же самое:

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

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

Ответ 6

Это будет более чистым, если вы закодируете свои данные на 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));
        });
    }
}

Ответ 7

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

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

Ответ 8

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

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

Ответ 10

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

Ответ 11

Если вы не хотите разбивать свои данные вместе с обратным вызовом 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
});

Этот подход изменяет входящий запрос, но как только вы закончите свой ответ, запрос будет собран с мусором, поэтому это не должно быть проблемой.

Перспективным подходом было бы сначала проверить размер тела, если вы боитесь огромных тел.

Ответ 12

1) Установите 'body-parser' из npm.

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;

Ответ 13

Если вы предпочитаете использовать чистый 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}');
});

Ответ 14

Существует несколько способов сделать это. Однако самый быстрый способ, который я знаю, - использовать библиотеку Express.js с body-parser.

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 на bodyParser.json, а если данные POST содержат массив JSON.

Дополнительная информация: http://www.kompulsa.com/how-to-accept-and-parse-post-requests-in-node-js/

Ответ 15

Вам нужно получить данные POST в кусках, используя request.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)

Вам следует рассмотреть вопрос о добавлении ограничения размера в указанной позиции как thejh, предложенного.

Ответ 16

Если вы используете Express.js, перед тем, как вы сможете получить доступ к req.body, вы должны добавить посредник bodyParser:

app.use(express.bodyParser());

Затем вы можете запросить

req.body.user

Ответ 17

И если вы не хотите использовать всю фреймворк, например Express, но вам также нужны разные типы форм, включая закачки, то formaline может быть хорошим выбором.

Он указан в Node.js-модулях

Ответ 18

Я нашел видео, в котором объясняется, как этого добиться: 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);

Ответ 19

Для тех, кто использует необработанную двоичную загрузку 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!");
  });
});

Ответ 20

Вы можете использовать экспресс- промежуточное программное обеспечение, в котором теперь встроен body-parser. Это означает, что все, что вам нужно сделать, это следующее:

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

Этот пример кода - ES6 с Express 4.16.x

Ответ 21

вы можете извлечь параметр 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: и HTML FORM IS.

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

Я надеюсь, что это сработает для вас. Спасибо.

Ответ 22

Ограничьте размер POST, чтобы избежать наводнения вашего приложения node. Существует отличный raw-body модуль, подходящий как для экспресс-подключения, так и для подключения, который может помочь вам ограничить запрос по размеру и длине.

Ответ 23

Если это связано с загрузкой файла, браузер обычно отправляет его как "multipart/form-data" content-type. Вы можете использовать это в таких случаях

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

Ссылка 1

Ссылка 2

Ответ 24

В полях формы, подобных этим

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

некоторые из приведенных выше ответов не будут выполнены, поскольку они поддерживают только плоские данные.

В настоящее время я использую ответ Кейси Чу, но вместо "qs" вместо модуля "querystring". Это также модуль "body-parser" . Поэтому, если вам нужны вложенные данные, вам нужно установить 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.
        });
    }
}

Ответ 25

Это должно работать:

app.use(bodyParser.json());

app.post("/want_pay", function(req, res){

var val=req.body.your_value; 

console.log(val);
});

Ответ 26

Вы можете легко отправить и получить ответ на запрос POST, используя "Запрос - упрощенный HTTP-клиент" и Javascript Promise.

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

Ответ 27

Вам нужно использовать bodyParser(), если вы хотите, чтобы данные формы были доступны в req.body. body-parser анализирует ваш запрос и преобразует его в формат, из которого вы можете легко извлечь необходимую информацию, которая может вам понадобиться.

Например, допустим, у вас есть форма регистрации на вашем веб-интерфейсе. Вы заполняете его и запрашиваете у сервера сохранить данные где-нибудь.

Извлечение имени пользователя и пароля из вашего запроса выполняется так же просто, как показано ниже, если вы используете body-parser.

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

var loginDetails = {

username : request.body.username,

password : request.body.password

};

Ответ 28

Express v4.17.0

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