web-dev-qa-db-fra.com

Comment traiter POST données dans Node.js?

Comment extraire les données de formulaire (form[method="post"]) et les téléchargements de fichiers envoyés à partir de la méthode HTTP POST dans Node.js ?

J'ai lu la documentation, googlé et rien trouvé.

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

Y a-t-il une bibliothèque ou un hack?

536
Ming-Tang

Si vous utilisez Express (développement Web performant et de grande classe pour Node.js), vous pouvez procéder comme suit:

HTML:

<form method="post" action="/">
    <input type="text" name="user[name]">
    <input type="text" name="user[email]">
    <input type="submit" value="Submit">
</form>

JavaScript:

app.use(express.bodyParser());

app.post('/', function(request, response){
    console.log(request.body.user.name);
    console.log(request.body.user.email);
});

MIS À JOUR LE 1/juin/2016:

La méthode ci-dessus est déconseillée, utilisez maintenant:

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

Vous pouvez utiliser le module 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.
        });
    }
}

Par exemple, si vous avez un champ input portant le nom age, vous pouvez y accéder à l’aide de la variable post:

console.log(post.age);
662
Casey Chu

Assurez-vous de tuer la connexion si quelqu'un essaye d'inonder votre 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

        });
    }
}
137
thejh

Voici un très simple wrapper sans cadre basé sur les autres réponses et articles postés ici:

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

Exemple d'utilisation:

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

Il sera plus propre si vous encodez vos données enJSON, puis envoyez-les à 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));
        });
    }
}
75
Lewis

Beaucoup de réponses ici ne sont plus de bonnes pratiques ou n'expliquent rien, c'est pourquoi j'écris ceci.

Lorsque le rappel de http.createServer est appelé, c'est lorsque le serveur a effectivement reçu tous les en-têtes de la demande, mais il est possible que les données n'aient pas encore été reçues. Nous devons donc les attendre. L'objet de requête http (une instance http.IncomingMessage) est en réalité un lisibleflux . Dans les flux lisibles, chaque fois qu'un bloc de données arrive, un événement dataest émis (en supposant que vous ayez enregistré un rappel) et lorsque tous les morceaux sont arrivés, un événement end est émis. Voici un exemple sur la façon dont vous écoutez les événements: 

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)

Si vous essayez ceci, vous remarquerez que les morceaux sont buffers . Si vous ne traitez pas de données binaires et que vous devez travailler avec des chaînes, je vous suggère d'utiliser request.setEncoding method, qui entraîne le flux à émettre des chaînes interprétées avec le codage donné et à gérer correctement les caractères multi-octets.

Maintenant, chaque morceau ne vous intéresse probablement pas, alors dans ce cas, vous voulez probablement le mettre en mémoire tampon comme ceci:

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)

Ici Buffer.concat est utilisé, ce qui concatène simplement tous les tampons et renvoie un gros tampon. Vous pouvez également utiliser le module concat-stream qui fait la même chose:

const http = require('http');
const concat = require('concat-stream');
http.createServer((request, response) => {
  concat(request, data => {
    console.log('Data: ', data);
  });
}).listen(8080)

Si vous essayez d'accepter la soumission de formulaires HTML POST sans fichiers ni handing jQuery ajax appelle avec le type de contenu par défaut, le type de contenu est alors application/x-www-form-urlencoded avec le codage uft-8. Vous pouvez utiliser le module querystring pour le désérialiser et accéder aux propriétés:

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)

Si votre type de contenu est JSON, vous pouvez simplement utiliser JSON.parse au lieu de qs.parse .

Si vous traitez avec des fichiers ou manipulez un type de contenu en plusieurs parties, dans ce cas, vous devriez utiliser quelque chose comme formidable qui élimine toute la douleur de le gérer. Jetez un coup d’œil à cette autre réponse de la mienne où j’ai posté des liens utiles et des modules pour le contenu en plusieurs parties.

Si vous ne souhaitez pas analyser le contenu mais le transférer ailleurs, par exemple, envoyez-le à une autre requête http en tant que données ou enregistrez-le dans un fichier que je suggère en le piping plutôt que de le mettre en mémoire tampon, Sera moins de code, gère mieux la contre-pression, il faudra moins de mémoire et dans certains cas plus rapide.

Donc, si vous voulez enregistrer le contenu dans un fichier:

 http.createServer((request, response) => {
   request.pipe(fs.createWriteStream('./request'));
 }).listen(8080)

Comme d'autres réponses l'ont noté, gardez à l'esprit que des clients malveillants peuvent vous envoyer une énorme quantité de données afin de bloquer votre application ou de remplir votre mémoire afin de la protéger, afin de vous assurer que vous supprimez les demandes qui émettent des données dépassent une certaine limite. Si vous n'utilisez pas de bibliothèque pour gérer les données entrantes. Je suggérerais d'utiliser quelque chose comme stream-meter qui peut annuler la demande si atteint la limite spécifiée:

limitedStream = request.pipe(meter(1e7));
limitedStream.on('data', ...);
limitedStream.on('end', ...);

ou 

request.pipe(meter(1e7)).pipe(createWriteStream(...));

ou 

concat(request.pipe(meter(1e7)), ...);

Essayez également d'utiliser des modules npm plutôt que de les implémenter vous-même, car ils seront probablement mieux à même de traiter les cas Edge. Pour exprimer, je suggère d'utiliser body-parser . Pour koa, il existe un module similaire .

Si vous n'utilisez pas de cadre, body est plutôt bon.

74
Farid Nouri Neshat

Pour ceux qui se demandent comment faire cette tâche triviale sans installer un framework web, j'ai réussi à le faire. À peine prêt pour la production mais cela semble fonctionner.

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);
        })
    }
}
33
Shawn Whinnery

Vous pouvez utiliser body-parser, le middleware d'analyse de corps Node.js.

Premier chargement body-parser 

$ npm install body-parser --save

Quelques exemples de code

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

Plus de documentation peut être trouvé ici

9
sourcecode

Référence: https://nodejs.org/fr/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
});
8
Udhaya

Voici comment vous pouvez le faire si vous utilisez 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);
    // ...
});
6
Dmitry

1) Installez 'body-parser' à partir de npm.

2) Puis dans votre app.ts  

var bodyParser = require('body-parser');

3) alors vous devez écrire 

app.use(bodyParser.json())

dans app.ts module

4) gardez à l'esprit que vous incluez 

app.use(bodyParser.json())

dans le haut ou avant toute déclaration de module.

Ex: 

app.use(bodyParser.json())
app.use('/user',user);

5) Ensuite, utilisez 

var postdata = req.body;
4
Er Shubham Patidar

Si vous ne souhaitez pas fragmenter vos données avec le rappel data, vous pouvez toujours utiliser le rappel readable comme ceci:

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

Cette approche modifie la demande entrante, mais dès que vous avez terminé votre réponse, la demande sera mise au rebut, ce qui ne devrait pas poser de problème.

Une approche avancée serait de vérifier la taille du corps en premier, si vous avez peur des corps énormes.

4
Thomas Fankhauser

Vous devez recevoir les données POST en morceaux à l'aide de 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)

Vous devriez envisager d’ajouter une limite de taille à la position indiquée sous la forme thejh suggéré .

4
Zaz

Il y a plusieurs façons de le faire. Cependant, le moyen le plus rapide que je connaisse consiste à utiliser la bibliothèque Express.js avec un analyseur de corps.

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

Cela peut fonctionner pour les chaînes, mais je changerais bodyParser.urlencoded en bodyParser.json si les données POST contiennent un tableau JSON.

Plus d'infos: http://www.kompulsa.com/how-to-accept-and-parse-post-requests-in-node-js/

4
nikodean2

Si vous utilisez Express.js , avant de pouvoir accéder à req.body, vous devez ajouter le middleware bodyParser:

app.use(express.bodyParser());

Ensuite, vous pouvez demander

req.body.user
3
PatricioS

Si vous préférez utiliser Node.js pur, vous pouvez extraire les données POST comme indiqué ci-dessous:

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

3
Oleksii Trekhleb

Et si vous ne souhaitez pas utiliser l'intégralité de la structure, comme Express, mais que vous avez également besoin de différents types de formulaires, y compris les téléchargements, alors formaline peut être un bon choix.

Il est listé dans Node.js modules

2
Pavel Koryagin

Vous pouvez utiliser le express middleware, qui intègre désormais un analyseur de corps. Cela signifie que tout ce que vous devez faire est le suivant:

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

Cet exemple de code est ES6 avec Express 4.16.x

1
Big Money

J'ai trouvé une vidéo qui explique comment y parvenir: https://www.youtube.com/watch?v=nuw48-u3Yrg

Il utilise le module "http" par défaut avec les modules "querystring" et "stringbuilder". L'application prend deux nombres (à l'aide de deux zones de texte) à partir d'une page Web et, lors de la soumission, renvoie la somme de ces deux (avec la persistance des valeurs dans les zones de texte). C’est le meilleur exemple que je puisse trouver ailleurs.

Code source associé:

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

Pour ceux qui utilisent raw binary POST upload sans surcharge d'encodage, vous pouvez utiliser:

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

serveur:

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!");
  });
});
1
lukyer

Vous pouvez facilement envoyer et obtenir la réponse de la demande POST en utilisant "Demande - Client HTTP simplifié" et la promesse 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);
            }
        });
    });
}
0
Kaveesha Baddage

S'il s'agit d'un téléchargement de fichier, le navigateur l'envoie généralement en tant que "multipart/form-data" contenu-type ..__

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

Référence 1

Référence 2

0
user3526

vous pouvez extraire le paramètre post sans utiliser express.

1: nmp install multiparty

2: importation multipartie. comme 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: et HTML FORM IS.

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

J'espère que cela fonctionnera pour vous. Merci.

0
Maneesh Singh

Vous devez utiliser bodyParser () si vous souhaitez que les données du formulaire soient disponibles dans req.body. body-parser analyse votre demande et la convertit dans un format permettant d'extraire facilement les informations pertinentes dont vous pourriez avoir besoin.

Par exemple, supposons que vous ayez un formulaire d’inscription à votre interface. Vous le remplissez et demandez au serveur de sauvegarder les détails quelque part.

Extraire le nom d’utilisateur et le mot de passe de votre requête s’effectue aussi simplement que ci-dessous si vous utilisez body-parser.

…………………………………………………….

var loginDetails = {

username : request.body.username,

password : request.body.password

};
0
Rubin bhandari

Sur des champs de formulaire comme ceux-ci 

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

certaines des réponses ci-dessus vont échouer car elles ne prennent en charge que des données à plat.

Pour l'instant, j'utilise la réponse Casey Chu mais avec le module "qs" au lieu du module "querystring" C'est le module "body-parser" utilise également. Donc, si vous voulez des données imbriquées, vous devez installer qs. 

npm install qs --save

Puis remplacez la première ligne comme suit:

//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.
        });
    }
}
0
Geza Turi

Limiter la taille POST pour éviter d'inonder votre application de nœud . Il existe un excellent module raw-body , qui convient à la fois aux services express et de connexion, qui peut vous aider à limiter la demande en taille et en longueur.

0
EricSonaron