Ответы:
Если вы используете 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)
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)
});
app.use(express.bodyParser());
.
Вы можете использовать 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);
var POST = qs.parse(body); // use POST
только для таких нубов, как я: если имя поля ввода текста «пользователь», Post.user
будут отображаться данные этого поля. Напримерconsole.log(Post.user);
readable
обратный вызов вместо встраивания данных в строку тела. После того, как его уволят, тело доступно черезrequest.read();
req.connection.destroy();
это не мешает выполнению обратных вызовов! Например, обратный вызов "on end" будет выполнен с усеченным телом! Это, вероятно, не то, что вы хотите ...
Обязательно разорвите соединение, если кто-то попытается заполнить вашу 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 POST = qs.parse(body); // use POST
только для нубов: когда имя поля ввода текста «пользователь», Post.user покажет данные этого поля. например console.log (Post.user);
Многие ответы здесь больше не являются хорошей практикой или ничего не объясняют, поэтому я и пишу это.
Когда вызывается обратный вызов 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
кодировкой. Вы можете использовать модуль 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)), ...);
В то время как я описал выше, как вы можете использовать тело HTTP-запроса, для простой буферизации и анализа содержимого, я предложил использовать один из этих модулей, а не реализовывать их самостоятельно, поскольку они, вероятно, будут лучше обрабатывать крайние случаи. Для экспресса я предлагаю использовать body-parser . Для Коа есть аналогичный модуль .
Если вы не используете рамки, тело довольно хорошо.
request
используется повторно и request.on('end')
вызывается несколько раз? Как я могу избежать этого?
request.on('end', ...)
будет вызываться.
Вот очень простая оболочка без фреймворка, основанная на других ответах и статьях, размещенных здесь:
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);
response.post
а не более логичным request.post
. Я обновил пост.
Будет лучше, если вы закодируете свои данные в 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));
});
}
}
qs.parse()
, чтобы JSON.parse()
превратить тело в нечто полезное. Пример:, var post = JSON.parse(body);
затем получите доступ к данным с помощью post.fieldname
. (Мораль истории, если вы не понимаете, что видите, не забывайте typeof
!)
request.setEncoding
чтобы заставить это работать должным образом, иначе это может не обрабатывать символы не ascii должным образом.
Для тех, кто интересуется, как выполнить эту тривиальную задачу без установки веб-фреймворка, мне удалось собрать все вместе. Вряд ли производство готово, но, похоже, работает.
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);
})
}
}
Вы можете использовать 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);
})
Больше документации можно найти здесь
Ссылка: 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-formidable :
var formidable = require("formidable");
var form = new formidable.IncomingForm();
form.parse(request, function (err, fields) {
console.log(fields.parameter1);
console.log(fields.parameter2);
// ...
});
Если вы предпочитаете использовать чистый 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}`);
});
1) Установить '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;
Если вы не хотите разбивать свои данные на части вместе с 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
});
Этот подход изменяет входящий запрос, но как только вы закончите свой ответ, запрос будет собираться мусором, так что это не должно быть проблемой.
Продвинутым подходом было бы сначала проверить размер тела, если вы боитесь огромных тел.
request
является нормальным потоком node.js, поэтому вы можете проверить request.headers
длину тела и при необходимости прервать запрос.
Есть несколько способов сделать это. Однако самый быстрый способ, который я знаю, - это использовать библиотеку 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/
Вам нужно получать 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)
Вы должны рассмотреть возможность добавления ограничения размера в указанной позиции, как предложено .
setTimeout
который завершает соединение через определенный период времени, если полный запрос не получен в этом окне.
Если вы используете Express.js , прежде чем вы сможете получить доступ к req.body, вы должны добавить middleware bodyParser:
app.use(express.bodyParser());
Тогда вы можете попросить
req.body.user
И если вы не хотите использовать весь фреймворк, такой как Express, но вам также нужны разные виды форм, в том числе загрузки, тогда формалинайн может быть хорошим выбором.
Это перечислено в модулях Node.js
Я нашел видео, которое объясняет, как этого добиться: 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);
Для тех, кто использует сырую двоичную загрузку 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!");
});
});
Вы можете использовать промежуточное программное обеспечение 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)
})
Этот пример кода ES6 с Express 4.16.x
Вы можете извлечь параметр сообщения без использования экспресс.
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 method=POST enctype=multipart/form-data>
<input type=text name=userfile1><br>
<input type=submit>
</form>
Я надеюсь, что это будет работать для вас. Спасибо.
Ограничьте размер POST, чтобы избежать затопления вашего узла приложения. Существует отличный модуль raw-body , подходящий как для экспресс, так и для соединения, который может помочь вам ограничить запрос по размеру и длине.
На полях формы, как эти
<input type="text" name="user[name]" value="MyName">
<input type="text" name="user[email]" value="myemail@somewherefarfar.com">
некоторые из приведенных выше ответов потерпят неудачу, потому что они поддерживают только плоские данные.
Сейчас я использую ответ Кейси Чу, но с модулем «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.
});
}
}
Вы можете легко отправить и получить ответ на запрос 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);
}
});
});
}
Вам нужно использовать bodyParser (), если вы хотите, чтобы данные формы были доступны в req.body. body-parser анализирует ваш запрос и преобразует его в формат, из которого вы можете легко извлечь необходимую информацию.
Например, предположим, у вас есть форма регистрации на вашем веб-интерфейсе. Вы заполняете его и запрашиваете сервер, чтобы сохранить данные где-нибудь.
Извлечение имени пользователя и пароля из вашего запроса выполняется так же просто, как показано ниже, если вы используете body-parser.
.............................................................
var loginDetails = {
username : request.body.username,
password : request.body.password
};
ОДИН ЛАЙНЕР без СРЕДНЕГО ОБЕСПЕЧЕНИЯ
Если вы публикуете следующие данные, то 'name':'ABC'
вы можете проанализировать их, используя следующий один лайнер,
require('url').parse(req.url, true).query.name