web-dev-qa-db-fra.com

Comment gérer la requête POST dans node.js

J'essaie de gérer une demande de publication envoyée à mon serveur node.js. Le fichier JavaScript avec un nom server.js affiche un formulaire sur le navigateur. Je veux accéder aux valeurs du formulaire après leur publication sur le backend node.js.

Le formulaire contient un nom d'utilisateur, un référentiel et une branche. Lorsque le formulaire est soumis, je souhaite afficher ces données à l'utilisateur.

Le code server.js:

var http = require('http');

http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/html'});
response.end('<html><body>'
    + '<h1>XYZ Repository Commit Monitor</h1>'
    + '<form method="post" action="." enctype="application/x-www-form-urlencoded"><fieldset>'
    + '<div><label for="UserName">User Name:</label><input type="text" id="UserName" name="UserName" /></div>'
    + '<div><label for="Repository">Repository:</label><input type="text" id="Repository" name="Repository" /></div>'
    + '<div><label for="Branch">Branch:</label><input type="text" id="Branch" name="Branch" value="master" /></div>'
    + '<div><input id="ListCommits" type="submit" value="List Commits" /></div>'
    + '</fieldset></form>'
    + '</body></html>');
}).listen(8124);

console.log('Server running at http://127.0.0.1:8124/');
45
Sau

Je vais utiliser le code que vous avez fourni et fournir une réponse plus approfondie que ce qui est couvert dans votre question pour accueillir les gens de The Distant Future. Je vais également fournir une réponse qui utilise "Vanilla JS" ( http://www.Vanilla-js.com/ ) parce que je pense que trop de hipsters disent "utiliser un framework" lorsque vous essayez pour savoir comment cela fonctionne. Je pense que la raison pour laquelle ils le font est parce que quelqu'un leur a dit "d'utiliser un cadre" lorsqu'ils apprenaient comment cela fonctionne. Parce qu'ils ne sont pas des hackers, ils ne se sont pas souciés d'essayer de comprendre le processus, donc très souvent beaucoup d'entre eux ne comprennent pas comment le faire par eux-mêmes, sans framework (d'où l'omniprésent "utiliser un framework"). Vous deviendrez un meilleur pirate en comprenant ce qui se passe sous le capot et j'espère que cette réponse vous aidera à cet égard.

Maintenant que vous souhaitez accepter les données POST (formulaire) via le formulaire que vous sortez, il est nécessaire de fournir un mécanisme de routage dans votre serveur. Cela signifie que vous demanderez à votre serveur de donner le formulaire aux personnes visitant votre site, mais si l'utilisateur soumet un formulaire, Node acheminera les données POST vers un petit traitement une fonction. J'ai d'abord fourni la réponse complète, puis je l'ai disséquée plus loin, pour accueillir les personnes qui souhaitent apprendre du code.

var http = require('http');
var qs = require('querystring');
var formOutput = '<html><body>'
  + '<h1>XYZ Repository Commit Monitor</h1>'
  + '<form method="post" action="inbound" enctype="application/x-www-form-urlencoded"><fieldset>'
  + '<div><label for="UserName">User Name:</label><input type="text" id="UserName" name="UserName" /></div>'
  + '<div><label for="Repository">Repository:</label><input type="text" id="Repository" name="Repository" /></div>'
  + '<div><label for="Branch">Branch:</label><input type="text" id="Branch" name="Branch" value="master" /></div>'
  + '<div><input id="ListCommits" type="submit" value="List Commits" /></div></fieldset></form></body></html>';
var serverPort = 8124;
http.createServer(function (request, response) {
  if(request.method === "GET") {
    if (request.url === "/favicon.ico") {
      response.writeHead(404, {'Content-Type': 'text/html'});
      response.write('<!doctype html><html><head><title>404</title></head><body>404: Resource Not Found</body></html>');
      response.end();
    } else {
      response.writeHead(200, {'Content-Type': 'text/html'});
      response.end(formOutput);
    }
  } else if(request.method === "POST") {
    if (request.url === "/inbound") {
      var requestBody = '';
      request.on('data', function(data) {
        requestBody += data;
        if(requestBody.length > 1e7) {
          response.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'});
          response.end('<!doctype html><html><head><title>413</title></head><body>413: Request Entity Too Large</body></html>');
        }
      });
      request.on('end', function() {
        var formData = qs.parse(requestBody);
        response.writeHead(200, {'Content-Type': 'text/html'});
        response.write('<!doctype html><html><head><title>response</title></head><body>');
        response.write('Thanks for the data!<br />User Name: '+formData.UserName);
        response.write('<br />Repository Name: '+formData.Repository);
        response.write('<br />Branch: '+formData.Branch);
        response.end('</body></html>');
      });
    } else {
      response.writeHead(404, 'Resource Not Found', {'Content-Type': 'text/html'});
      response.end('<!doctype html><html><head><title>404</title></head><body>404: Resource Not Found</body></html>');
    }
  } else {
    response.writeHead(405, 'Method Not Supported', {'Content-Type': 'text/html'});
    return response.end('<!doctype html><html><head><title>405</title></head><body>405: Method Not Supported</body></html>');
  }
}).listen(serverPort);
console.log('Server running at localhost:'+serverPort);

Et maintenant pour la ventilation expliquant pourquoi j'ai fait les choses que j'ai faites.

var http = require('http');
var qs = require('querystring');

Tout d'abord, vous allez ajouter le module intégré de "chaîne de requête" de Node pour analyser les données de formulaire réelles.

var formOutput = '<html><body>'
  + '<h1>XYZ Repository Commit Monitor</h1>'
  + '<form method="post" action="/inbound" enctype="application/x-www-form-urlencoded"><fieldset>'
  + '<div><label for="UserName">User Name:</label><input type="text" id="UserName" name="UserName" /></div>'
  + '<div><label for="Repository">Repository:</label><input type="text" id="Repository" name="Repository" /></div>'
  + '<div><label for="Branch">Branch:</label><input type="text" id="Branch" name="Branch" value="master" /></div>'
  + '<div><input id="ListCommits" type="submit" value="List Commits" /></div></fieldset></form></body></html>';
var serverPort = 8124;

J'ai déplacé la sortie du formulaire au-dessus de notre mécanisme de serveur/routage/gestion de formulaire, car la logique est alors beaucoup plus facile à lire. J'ai également déplacé les informations sur le port d'écoute du serveur ici, car vous n'avez alors qu'à les modifier à un endroit au lieu de plusieurs ci-dessous.

http.createServer(function (request, response) {

(Je raccourcis généralement les paramètres de cette fonction à "req" et "res", mais c'est juste ma préférence.)

  if(request.method === "GET") {
    if (request.url === "/favicon.ico") {
      response.writeHead(404, {'Content-Type': 'text/html'});
      response.write(notFound);
      response.end();

Ici, j'ai inclus un exemple de routage simple. Dans ce cas, notre serveur écoute les demandes de "favicon.ico" - une demande faite avec presque toutes les demandes initiales de page Web par tous les principaux navigateurs. Ce fichier est la petite icône que vous pouvez voir dans les onglets de chaque page Web que vous visitez. Pour nos besoins, nous n'avons pas besoin de servir un favicon, mais nous traiterons les demandes entrantes pour qu'il affiche des mécanismes de routage de base.

    } else {
      response.writeHead(200, {'Content-Type': 'text/html'});
      response.end(formOutput);
    }

Si vos visiteurs pointent leur navigateur vers N'IMPORTE QUELLE autre ressource sur votre serveur avec la méthode GET par défaut (en plus du "favicon.ico" que nous venons de gérer ci-dessus), nous leur servirons le formulaire.

  } else if(request.method === "POST") {

Sinon, si vos visiteurs pointent un POST vers votre serveur, il est très probable qu'ils aient soumis le formulaire qu'ils ont récupéré avec la demande GET précédente.

    if (request.url === "/inbound") {

Ici, nous écoutons les demandes entrantes appelées "/ inbound" qui - si vous avez saisi le petit détail ci-dessus - est "l'action" de notre formulaire HTML. Comme vous le savez peut-être, l '"action" du formulaire indique au navigateur où envoyer les données du formulaire.

      var requestBody = '';
      request.on('data', function(data) {
        requestBody += data;
        if(requestBody.length > 1e7) {
          response.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'});
          response.end('<!doctype html><html><head><title>413</title></head><body>413: Request Entity Too Large</body></html>');
        }
      });
      request.on('end', function() {
        var formData = qs.parse(requestBody);

Cela peut sembler un peu déroutant, mais je promets que non. POST les demandes peuvent être envoyées sous forme de messages en plusieurs parties à partir du navigateur client. Avec quelque chose d'aussi petit que quelques variables dans un formulaire, vous ne le verrez probablement jamais, mais à mesure que vous augmentez la quantité de données que vous gérez, vous le verrez. Si vous êtes attentif, vous verrez également l'instruction if() demandant la longueur des données POST. Une personne malveillante peut tuer votre serveur en téléchargeant un fichier sans fin, mais pas si nous prenons des mesures. Cela limite le corps de données POST à environ dix mégaoctets, mais vous devez ajuster en conséquence. Connaître ces choses empêche un futur mal de tête, et je ne veux pas que vous ayez mal à la tête.

        response.writeHead(200, {'Content-Type': 'text/html'});
        response.write('<!doctype html><html><head><title>response</title></head><body>');
        response.write('Thanks for the data!<br />User Name: '+formData.UserName);
        response.write('<br />Repository Name: '+formData.Repository);
        response.write('<br />Branch: '+formData.Branch);
        response.end('</body></html>');
      });

Et c'est là que nous utilisons les données du formulaire. En raison de la nature de Javascript, ces noms de variables sont SENSIBLES À LA CASE (tels que "UserName" au lieu de "username"). Bien sûr, vous pouvez faire tout ce que vous voulez avec ces données (en gardant à l'esprit la boucle d'événements de Node et la nature asynchrone).

    }
    response.writeHead(404, 'Resource Not Found', {'Content-Type': 'text/html'});
    return response.end('<!doctype html><html><head><title>404</title></head><body>413: Request Entity Too Large</body></html>');

Pour continuer notre exemple de routage, ce que nous avons fait ici est inclus un fourre-tout sous l'instruction if() qui envoie au client une réponse générique 404 "Not Found" à toute demande POST nous n'avons pas déjà géré.

  } else {
    response.writeHead(405, 'Method Not Supported', {'Content-Type': 'text/html'});
    return response.end('<!doctype html><html><head><title>405</title></head><body>405: Method Not Supported</body></html>');
  }
}).listen(serverPort);
console.log('Server running at localhost:'+serverPort);

Et maintenant, nous venons de terminer le code, y compris un peu de code pour gérer les demandes avec des méthodes étranges. Il y a quelques points que je n'ai pas abordés (structure de fonction, données de formulaire vides, etc.), mais il existe en effet de nombreuses façons d'atteindre vos objectifs. Comme l'un de mes professeurs CS l'a dit il y a de nombreuses années, il existe tellement de façons de programmer un programme qu'il est facile de voir qui triche en partageant ses devoirs.

J'espère que vous (et n'importe qui d'autre) pouvez voir que ce n'est pas un processus ésotérique ou même légèrement difficile de faire des choses dans Node en utilisant ses modules intégrés au lieu de s'appuyer sur des bibliothèques tierces externes telles qu'Express . Ces bibliothèques ont leur place dans le monde, mais ne suivez pas le troupeau: prenez une décision éclairée à propos de votre code, car en fin de compte, vous en êtes le responsable (pas certaines personnes sur Stack Overflow).

146
L0j1k