Cum fac sa extrag datele din formular (formular[metoda="post"]`) și încărcări de fișiere trimise de la HTTP "POST" metoda în Node.js?
Am'am citit documentația, căutat pe google și nu am găsit nimic.
function (request, response) {
//request.post????
}
Există o bibliotecă sau un hack?
Puteți utiliza querystring
module:
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.
});
}
}
Acum, de exemplu, dacă ai o "intrare" câmp cu numele de "vârstă", ai putea accesa folosind variabila "post":
console.log(post.age);
Dacă utilizați Exprime (de înaltă performanță, de înaltă clasă, dezvoltare web pentru Node.js), puteți face acest lucru:
HTML:
<form method="post" action="/">
<input type="text" name="user[name]">
<input type="text" name="user[email]">
<input type="submit" value="Submit">
</form>
API client:
fetch('/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
user: {
name: "John",
email: "[email protected]"
}
})
});
Node.js: (deoarece Exprima 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: (pentru 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)
});
Asigurați-vă că să-l omoare conexiunea, dacă cineva încearcă să-ți inund 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
});
}
}
Aici's-o foarte simplu, nu-cadru înveliș bazează pe alte răspunsuri și articolele postate aici:
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();
}
}
Exemplu de utilizare:
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);
O mulțime de răspunsuri aici nu sunt de bune practici sau nu't explica nimic, așa că's de ce am'm scris acest lucru.
Atunci când apel invers de http.createServer este numit, este atunci când serverul de fapt au primit toate antetele de cerere, dar's posibil ca datele nu au fost primite încă, așa că trebuie să așteptați pentru ea. A cerere http obiect(un http.IncomingMessage exemplu) este de fapt o citit stream. În ușor de citit fluxuri ori de câte ori o bucată de date ajunge, o data
eveniment este emisă(presupunând că v-ați înregistrat un apel invers pentru a) și atunci când toate bucățile au ajuns o end
eveniment este emis. Aici's un exemplu despre cum ai asculta la evenimente:
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)
Dacă încercați acest lucru, veți observa bucăți sunt tampoane. Dacă nu sunteți de-a face cu date binare și necesitatea de a lucra cu siruri de caractere în loc sugerez să utilizați request.setEncoding metoda care provoacă fluxul emite siruri de caractere interpretate cu date de codare și se ocupă de caractere multi-byte în mod corespunzător.
Acum, vă sunt, probabil, interesat în fiecare bucată de l's proprii, astfel încât în acest caz, probabil, vrei să-tampon astfel:
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)
Aici Buffer.concat este folosit, care pur și simplu concateneaza toate rezervele și a reveni un tampon mare. Puteți folosi, de asemenea, concat-stream modul care face acelasi lucru:
const http = require('http');
const concat = require('concat-stream');
http.createServer((request, response) => {
concat(request, data => {
console.log('Data: ', data);
});
}).listen(8080)
Dacă sunteți încercarea de a accepta formularele HTML POST depunerea cu nr fișiere sau predarea jQuery ajax apeluri cu default tip de conținut, apoi tipul de conținut este application/x-www-form-urlencoded " cu " tum-8
codare. Puteți utiliza querystring modul pentru a de-serializarea și accesați proprietățile:
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)
În cazul în care conținutul este de tip JSON în schimb, puteți folosi pur și simplu JSON.parse în loc de qs.parse.
Dacă ai de-a face cu fișiere sau manipulare cu mai multe tip de conținut, apoi, în acest caz, ar trebui să utilizați ceva de genul formidabil care elimină durerea de-a face cu ea. Avea o privire la acest alt răspuns](https://stackoverflow.com/a/23718166/774086) de-al meu unde am postat link-uri utile și module pentru mai multe părți de conținut.
Dacă tu nu't vreau pentru a analiza de conținut, ci mai degrabă trece la altceva, de exemplu, trimite-l la un alt http solicita ca datele sau salvați-l într-un fișier sugerez tubulatura l, mai degrabă decât de tamponare, pentru ca'll fi mai puțin cod, se ocupă de contrapresiune mai bine, l'll să ia mai puțin de memorie și, în unele cazuri mai repede.
Deci, dacă doriți să salvați conținut într-un fișier:
http.createServer((request, response) => {
request.pipe(fs.createWriteStream('./request'));
}).listen(8080)
Ca și alte răspunsuri au remarcat păstra în mintea mea că malware clienții ar putea trimite o cantitate mare de date pentru a bloca cererea dumneavoastră sau umple memoria astfel încât să protejeze că asigurați-vă că fixați cereri care emit date trece de o anumită limită. Dacă tu nu't folosi o bibliotecă pentru a gestiona datele de intrare. Aș sugera folosind ceva de genul stream-meter, care poate anula cererea, dacă ajunge la limita specificată:
limitedStream = request.pipe(meter(1e7));
limitedStream.on('data', ...);
limitedStream.on('end', ...);
sau
request.pipe(meter(1e7)).pipe(createWriteStream(...));
sau
concat(request.pipe(meter(1e7)), ...);
În timp ce am descris mai sus privind modul în care puteți utiliza cererea HTTP corpul, pur și simplu pentru a tamponare și analizarea conținutului, îți sugerez să utilizați unul dintre aceste module mai degrabă de punere în aplicare pe cont propriu, deoarece acestea vor ocupa de cazuri de margine mai bine. Pentru express am sugerăm să utilizați corp-parser. Pentru koa, acolo's a modul similar.
Dacă tu nu't folosi un cadru, corpul este destul de bun.
Acesta va fi mai curat dacă encode datele dvs. pentru a JSON, apoi trimite-l la 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));
});
}
}
Pentru oricine întrebam cum de a face această sarcină banală, fără a instala un cadru web am reusit sa plop asta împreună. Aproape gata de producție, dar se pare că funcționează.
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);
})
}
}
Puteți folosi corpul lui-parser-ul`, Node.js corpul parsarea middleware.
Prima sarcina s-parser`
$ npm install body-parser --save
Un exemplu de cod
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);
})
Mai multe documente pot fi găsite aici
Referință: 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
});
Aici este cum puteți face acest lucru dacă utilizați nod-formidabil:
var formidable = require("formidable");
var form = new formidable.IncomingForm();
form.parse(request, function (err, fields) {
console.log(fields.parameter1);
console.log(fields.parameter2);
// ...
});
Dacă preferați să utilizați pur Node.js atunci s-ar putea extrage date POST cum este prezentat mai jos:
// 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}`);
});
Instala'corp-parser'` de la npm.
Apoi, în app.ts
var bodyParser = require('body-parser');
app.use(bodyParser.json())
în app.ts modulul
app.use(bodyParser.json())
în partea de sus sau înainte de orice modul declarație.
Ex:
app.use(bodyParser.json())
app.use('/user',user);
var postdata = req.body;
Dacă tu nu't doriți să bucata ta de date, împreună cu "date" callback îl poți folosi întotdeauna "inteligibilă" callback astfel:
// 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
});
Această abordare modifică cererea de intrare, dar de indata ce ai terminat de răspuns la solicitarea va fi de gunoi colectat, astfel încât să nu ar trebui să fie o problemă.
Un sistem avansat de abordare ar fi de a verifica dimensiunea corpului în primul rând, dacă ai're-e frică de mare de organisme.
Ai nevoie pentru a primi "POST" de date în bucăți cu ajutorul cererea.pe('date', funcția(bucată) {...})`
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)
Tu ar trebui să ia în considerare adăugarea o limită de dimensiune de la poziția indicată ca thejh sugerat.
Există mai multe moduri de a face asta. Cu toate acestea, cel mai rapid mod de știu este de a utiliza Express.js biblioteca cu corpul-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);
Care pot lucra pentru siruri de caractere, dar mi-ar schimba bodyParser.urlencoded să bodyParser.json în schimb, în cazul în care POSTUL de date conține o matrice JSON.
Mai multe informatii: http://www.kompulsa.com/how-to-accept-and-parse-post-requests-in-node-js/
Și dacă tu nu't doriți să utilizați întregul cadru Expres, dar, de asemenea, nevoie de diferite tipuri de forme, inclusiv imagini, apoi formaline poate fi o alegere bună.
Acesta este listat în Node.js module
Am gasit un video care explică cum de a realiza acest lucru:
Folosește implicit "http" modulul împreună cu "querystring" și "stringbuilder" module. Aplicația are două numere (folosind două casete de text) de pe o pagină web și asupra prezinte, revine suma de cei doi (împreună cu persistența valorilor în casete de text). Acesta este cel mai bun exemplu, am putea găsi oriunde în altă parte.
Legate de codul sursă:
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);
Pentru cei care folosesc prime binar POST incarca fără codare aeriene vă puteți folosi:
client:
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!");
});
});