Risposte:
Se usi Express (sviluppo web ad alte prestazioni e di alta classe per Node.js), puoi farlo:
HTML:
<form method="post" action="/">
<input type="text" name="user[name]">
<input type="text" name="user[email]">
<input type="submit" value="Submit">
</form>
Client API:
fetch('/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
user: {
name: "John",
email: "john@example.com"
}
})
});
Node.js: (da 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: (per 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());
.
Puoi usare il querystring
modulo:
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.
});
}
}
Ora, ad esempio, se si dispone di un input
campo con nome age
, è possibile accedervi utilizzando la variabile post
:
console.log(post.age);
var POST = qs.parse(body); // use POST
solo per utenti come me: quando il nome del campo di testo di input è "user", Post.user
mostrerà i dati di quel campo. ad es.console.log(Post.user);
readable
callback invece di creare i dati in una stringa di body. Una volta sparato, il corpo è disponibile attraversorequest.read();
req.connection.destroy();
non impedisce l'esecuzione dei callback! Ad esempio il callback "on end" verrà eseguito con il corpo troncato! Questo non è probabilmente quello che vuoi ...
Assicurati di interrompere la connessione se qualcuno tenta di inondare la tua 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
solo per noob: quando il nome del campo di testo di input è "utente", Post.user mostrerà i dati di quel campo. ad esempio console.log (Post.user);
Molte risposte qui non sono più buone pratiche o non spiegano nulla, quindi è per questo che sto scrivendo questo.
Quando viene richiamato il callback di http.createServer, è quando il server ha effettivamente ricevuto tutte le intestazioni per la richiesta, ma è possibile che i dati non siano ancora stati ricevuti, quindi dobbiamo aspettarlo. L' oggetto richiesta http (un'istanza http.IncomingMessage) è in realtà un flusso leggibile . In flussi leggibili ogni volta che arriva un blocco di dati, viene emesso un evento (supponendo che sia stato registrato un callback ad esso) e quando tutti i blocchi sono arrivati , viene emesso un evento. Ecco un esempio di come ascolti gli eventi: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)
Se provi questo, noterai che i blocchi sono buffer . Se non hai a che fare con dati binari e devi lavorare con le stringhe invece ti suggerisco di usare il metodo request.setEncoding che fa sì che il flusso emetta stringhe interpretate con la codifica data e gestisca correttamente i caratteri multibyte.
Ora probabilmente non sei interessato a ciascun pezzo da solo, quindi in questo caso probabilmente vuoi bufferizzarlo in questo modo:
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)
Qui viene utilizzato Buffer.concat , che concatena semplicemente tutti i buffer e restituisce un grosso buffer. Puoi anche usare il modulo concat-stream che fa lo stesso:
const http = require('http');
const concat = require('concat-stream');
http.createServer((request, response) => {
concat(request, data => {
console.log('Data: ', data);
});
}).listen(8080)
Se si sta tentando di accettare l'invio POST di moduli HTML senza file o passando le chiamate jQuery ajax con il tipo di contenuto predefinito, il tipo di contenuto è application/x-www-form-urlencoded
con uft-8
codifica. È possibile utilizzare il modulo Querystring per deserializzare il modulo e accedere alle proprietà:
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)
Se invece il tuo tipo di contenuto è JSON, puoi semplicemente usare JSON.parse invece di qs.parse .
Se hai a che fare con file o gestisci un tipo di contenuto multipart, allora in quel caso, dovresti usare qualcosa come formidabile che rimuove tutto il dolore dal gestirlo. Dai un'occhiata a questa mia altra risposta in cui ho pubblicato link e moduli utili per contenuti multipart.
Se non si desidera analizzare il contenuto ma piuttosto passarlo da qualche altra parte, ad esempio inviarlo a un'altra richiesta http come dati o salvarlo in un file, si consiglia di eseguire il piping anziché il buffering, poiché sarà inferiore codice, gestisce meglio la contropressione, ci vorrà meno memoria e in alcuni casi più veloce.
Quindi, se si desidera salvare il contenuto in un file:
http.createServer((request, response) => {
request.pipe(fs.createWriteStream('./request'));
}).listen(8080)
Come altre risposte hanno notato, mi viene in mente che i client malintenzionati potrebbero inviarti un'enorme quantità di dati per arrestare in modo anomalo la tua applicazione o riempire la tua memoria in modo da proteggere che assicuri di eliminare le richieste che emettono dati superano un certo limite. Se non si utilizza una libreria per gestire i dati in arrivo. Suggerirei di utilizzare qualcosa come stream-meter che può interrompere la richiesta se raggiunge il limite specificato:
limitedStream = request.pipe(meter(1e7));
limitedStream.on('data', ...);
limitedStream.on('end', ...);
o
request.pipe(meter(1e7)).pipe(createWriteStream(...));
o
concat(request.pipe(meter(1e7)), ...);
Mentre ho descritto sopra su come è possibile utilizzare il corpo della richiesta HTTP, per eseguire semplicemente il buffering e l'analisi del contenuto, suggerisco di utilizzare uno di questi moduli piuttosto che implementarlo da soli poiché probabilmente gestiranno meglio i casi limite. Per esprimere suggerisco di usare body-parser . Per koa, c'è un modulo simile .
Se non usi un framework, il corpo è abbastanza buono.
request
venga riutilizzata e venga request.on('end')
invocata più volte? Come posso evitarlo?
request.on('end', ...)
verrà chiamato.
Ecco un wrapper no-framework molto semplice basato sulle altre risposte e articoli pubblicati qui:
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();
}
}
Esempio di utilizzo:
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
piuttosto che più logico request.post
. Ho aggiornato il post.
Sarà più pulito se codifichi i tuoi dati su JSON , quindi li invii a 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()
, ha JSON.parse()
trasformato il corpo in qualcosa di utilizzabile. Esempio:, var post = JSON.parse(body);
quindi accedere ai dati con post.fieldname
. (Morale della storia, se sei confuso su ciò che stai vedendo, non dimenticare typeof
!)
request.setEncoding
per farlo funzionare correttamente altrimenti potrebbe non gestire correttamente i caratteri non ascii.
Per chiunque si chiedesse come svolgere questa banale attività senza installare un framework Web, sono riuscito a metterlo insieme. Difficilmente pronto per la produzione ma sembra funzionare.
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);
})
}
}
È possibile utilizzare body-parser
il middleware di analisi del corpo Node.js.
Primo carico body-parser
$ npm install body-parser --save
Qualche codice di esempio
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);
})
Più documentazione è disponibile qui
Riferimento: 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
});
Ecco come puoi farlo se usi il nodo formidabile :
var formidable = require("formidable");
var form = new formidable.IncomingForm();
form.parse(request, function (err, fields) {
console.log(fields.parameter1);
console.log(fields.parameter2);
// ...
});
Se si preferisce utilizzare Node.js puro, è possibile estrarre i dati POST come mostrato di seguito:
// 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) Installa 'body-parser'
da npm.
2) Quindi nel tuo app.ts
var bodyParser = require('body-parser');
3) quindi devi scrivere
app.use(bodyParser.json())
in app.ts modulo
4) tieni presente che includi
app.use(bodyParser.json())
nella parte superiore o prima di qualsiasi dichiarazione del modulo.
Ex:
app.use(bodyParser.json())
app.use('/user',user);
5) Quindi utilizzare
var postdata = req.body;
Se non si desidera raggruppare i dati insieme al data
callback, è sempre possibile utilizzare il readable
callback in questo modo:
// 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
});
Questo approccio modifica la richiesta in arrivo, ma una volta terminata la risposta, la richiesta verrà raccolta in modo inutile, quindi non dovrebbe essere un problema.
Un approccio avanzato sarebbe quello di controllare prima le dimensioni del corpo, se hai paura di corpi enormi.
request
è un normale flusso node.js, quindi puoi controllare la request.headers
lunghezza del corpo e annullare la richiesta se necessario.
Esistono diversi modi per farlo. Tuttavia, il modo più rapido che conosco è utilizzare la libreria Express.js con 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);
Questo può funzionare per le stringhe, ma cambierei bodyParser.urlencoded in bodyParser.json invece se i dati POST contengono un array JSON.
Maggiori informazioni: http://www.kompulsa.com/how-to-accept-and-parse-post-requests-in-node-js/
È necessario ricevere i POST
dati in blocchi utilizzandorequest.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)
Dovresti considerare l'aggiunta di un limite di dimensione nella posizione indicata, come suggerito dal jh .
setTimeout
che termina la connessione dopo un certo periodo di tempo, se la richiesta completa non viene ricevuta all'interno di quella finestra.
Se si utilizza Express.js , prima di poter accedere a req.body, è necessario aggiungere il middleware bodyParser:
app.use(express.bodyParser());
Quindi puoi chiedere
req.body.user
E se non vuoi usare l'intero framework come Express, ma hai anche bisogno di diversi tipi di moduli, inclusi i caricamenti, la formalina potrebbe essere una buona scelta.
È elencato nei moduli Node.js
Ho trovato un video che spiega come raggiungere questo obiettivo: https://www.youtube.com/watch?v=nuw48-u3Yrg
Utilizza il modulo "http" predefinito insieme ai moduli "querystring" e "stringbuilder". L'applicazione accetta due numeri (utilizzando due caselle di testo) da una pagina Web e, al momento dell'invio, restituisce la somma di questi due (insieme alla persistenza dei valori nelle caselle di testo). Questo è il miglior esempio che ho potuto trovare altrove.
Codice sorgente correlato:
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);
Per coloro che utilizzano il caricamento POST binario non elaborato senza overhead di codifica è possibile utilizzare:
cliente:
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);
server:
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!");
});
});
È possibile utilizzare il middleware express , che ora ha incorporato body-parser. Ciò significa che tutto ciò che devi fare è il seguente:
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)
})
Tale esempio di codice è ES6 con Express 4.16.x
puoi estrarre il parametro post senza usare express.
1: nmp install multiparty
2: importazione multiparty. comevar 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: e HTML FORM IS.
<form method=POST enctype=multipart/form-data>
<input type=text name=userfile1><br>
<input type=submit>
</form>
Spero che questo funzioni per te. Grazie.
Limitare le dimensioni POST per evitare di inondare l'app del nodo. Esiste un ottimo modulo raw-body , adatto sia per express che per connect, che può aiutarti a limitare la richiesta per dimensioni e lunghezza.
Se si tratta di un caricamento di file, il browser solitamente lo invia come tipo di "multipart/form-data"
contenuto. Puoi usarlo in questi casi
var multipart = require('multipart');
multipart.parse(req)
Su campi modulo come questi
<input type="text" name="user[name]" value="MyName">
<input type="text" name="user[email]" value="myemail@somewherefarfar.com">
alcune delle risposte di cui sopra falliranno perché supportano solo dati flat.
Per ora sto usando la risposta Casey Chu ma con il "qs" invece del modulo "querystring". Questo è anche il modulo "body-parser" . Quindi, se vuoi dati nidificati, devi installare qs.
npm install qs --save
Quindi sostituire la prima riga come:
//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.
});
}
}
È possibile inviare e ottenere facilmente la risposta della richiesta POST utilizzando "Richiesta - Client HTTP semplificato" e Promessa Javascript.
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);
}
});
});
}
È necessario utilizzare bodyParser () se si desidera che i dati del modulo siano disponibili in req.body. body-parser analizza la tua richiesta e la converte in un formato dal quale puoi facilmente estrarre le informazioni rilevanti di cui potresti aver bisogno.
Ad esempio, supponiamo che tu abbia un modulo di iscrizione nel tuo frontend. Lo stai compilando e stai richiedendo al server di salvare i dettagli da qualche parte.
L'estrazione di nome utente e password dalla tua richiesta è semplice come di seguito se usi body-parser.
.............................................................
var loginDetails = {
username : request.body.username,
password : request.body.password
};
UN LINER senza MIDDLEWARE
Se pubblichi i seguenti dati, 'name':'ABC'
puoi analizzarli utilizzando il seguente liner,
require('url').parse(req.url, true).query.name