Introducción a Node.js, parte 5: Enviar formularios por POST

Bueno, en la publicación anterior vimos cómo enviar formularios con el método GET, y luego recuperar los valores que se enviaron desde ese formulario a través de la url. Ahora bien, existen dos formas de recuperar datos enviados desde un formulario http, GET y POST, aunque hay otras más, por el momento veremos éstas. Y en esta ocasión aprenderemos a recuperar valores enviados desde un formulario mediante el método POST.

Bueno, aunque presumo que la mayoría de las personas que estén leyendo esto saben cuál es la diferencia entre enviar formularios por GET a enviarlos por POST no está de mal repasarlo. Cuando se envían datos al servidor mediante GET estos serán visibles en la url, mientras que por POST estarán ocultos. Enviar un formulario GET sería muy útil para por ejemplo un buscador, ya que luego podría copiarse esa url para recuperar la búsqueda. Mientras que POST sería útil para un formulario de login por ejemplo, ya que esos datos no deberían mostrarse en la url al enviar el formulario.

En esta ocasión haremos el siguiente ejercicio, habrá un formulario con dos campos, uno para ingresar el nombre y otro para un mensaje y un botón para enviar ambos al servidor y guardarlos en un array, que acto seguido mostrará el listado de todos los usuarios que hayan dejado su nombre y mensaje.

Para ello vamos a crear una nueva carpeta dentro de nuestros proyectos de Node.js y vamos a crear un archivo llamado index.js y a la misma altura una carpeta modulos que dentro tendrá un archivo llamado mensajes.js. Dentro de este último ingresaremos el siguiente código:

function dibujarCodigoHtml(mensajes_lista){
   var html = '<!DOCTYPE html>';
   html += '<html>';
   html += '<head>';
   html += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
   html += '</head>';
   html += '<body>';
   html += '<form action="" method="post">';
   html += '<label> Nombre </label> <br />';
   html += '<input type="text" name="nombre" required="required" /> <br />';
   html += '<label> Mensaje </label> <br />';
   html += '<textarea name="mensaje" required="required"></textarea> <br />';
   html += '<input type="submit" value="Enviar" />';
   html += '</form>';
   html += mostrarMensajes(mensajes_lista);
   html += '</body>';
   html += '</html>';
   return html;
}
function mostrarMensajes(mensajes_lista){
   var html = '<ul>';
   for(var i in mensajes_lista){
      html += '<li>';
      html += '<p> <strong> ' + mensajes_lista[i].nombre + ' </strong> dijo: </p>';
      html += '<p> ' + mensajes_lista[i].mensaje + ' </p>';
      html += '</li>';
   }
   html += '</ul>';
   return html;
}
exports.dibujarCodigoHtml = dibujarCodigoHtml;

Bueno, este módulo es muy parecido al de la publicación anterior. Tendremos una función llamada dibujarCodigoHtml() que recibirá el array con los mensajes guardados de los usuarios, y devolverá un código html con el formulario:

function dibujarCodigoHtml(mensajes_lista){
   var html = '<!DOCTYPE html>';
   html += '<html>';
   html += '<head>';
   html += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
   html += '</head>';
   html += '<body>';
   html += '<form action="" method="post">';
   html += '<label> Nombre </label> <br />';
   html += '<input type="text" name="nombre" required="required" /> <br />';
   html += '<label> Mensaje </label> <br />';
   html += '<textarea name="mensaje" required="required"></textarea> <br />';
   html += '<input type="submit" value="Enviar" />';
   html += '</form>';
   html += mostrarMensajes(mensajes_lista);
   html += '</body>';
   html += '</html>';
   return html;
}

A su vez dentro de éste se llamará a una función mostrarMensajes() que también recibirá la lista de los mensajes y devolverá un código html con los mismos:

function mostrarMensajes(mensajes_lista){
   var html = '<ul>';
   for(var i in mensajes_lista){
      html += '<li>';
      html += '<p> <strong> ' + mensajes_lista[i].nombre + ' </strong> dijo: </p>';
      html += '<p> ' + mensajes_lista[i].mensaje + ' </p>';
      html += '</li>';
   }
   html += '</ul>';
   return html;
}

Y finalmente exportamos la función dibujarCodigoHtml() para poder llamarlo desde el objeto que guarde este módulo:

exports.dibujarCodigoHtml = dibujarCodigoHtml;

Ahora vamos a editar nuestro archivo index.js para crear nuestro servidor:

var http = require('http');
var mensajes = require('./modulos/mensajes');
var mensajes_lista = new Array();
http.createServer(function(peticion, respuesta){
   respuesta.writeHead(200, {'Content-Type': 'text/html'});
   respuesta.end(mensajes.dibujarCodigoHtml(mensajes_lista));
}).listen(3000, '127.0.0.1');
console.log('Servidor funcionando.');

Bueno, con esto ya tenemos nuestra aplicación con el formulario para enviar los datos, pero aun nos falta la acción para recuperar esos datos por POST. Para ello vamos a editar nuevamente nuestro archivo index.js con el siguiente código:

var http = require('http');
var querystring = require('querystring');
var mensajes = require('./modulos/mensajes');
var mensajes_lista = new Array();
http.createServer(function(peticion, respuesta){
   if(peticion.method == 'POST'){
      var data_post = '';
      peticion.on('data', function(data_cortada){
         data_post += data_cortada;
      });
      peticion.on('end', function(){
         var data_post_objeto = querystring.parse(data_post);
         mensajes_lista.push({nombre: data_post_objeto.nombre, mensaje: data_post_objeto.mensaje});
         respuesta.writeHead(200, {'Content-Type': 'text/html'});
         respuesta.end(mensajes.dibujarCodigoHtml(mensajes_lista));
      });
   }else{
      respuesta.writeHead(200, {'Content-Type': 'text/html'});
      respuesta.end(mensajes.dibujarCodigoHtml(mensajes_lista));
   }
}).listen(3000, '127.0.0.1');
console.log('Servidor funcionando.');

Bueno por empezar llamamos a un nuevo módulos, querystring, ya veremos para qué.

Luego preguntamos si la petición ha venido por el método POST:

if(peticion.method == 'POST')

Osea si se ha enviado el formulario.

Luego recuperamos los datos enviados desde el formulario mediante el evento on() y el valor ‘data’:

var data_post = '';
peticion.on('data', function(data_cortada){
   data_post += data_cortada;
});

Iremos concatenando dentro de la variable data_post los valores que ha enviado el usuario desde el formulario. Esta variable finalmente tendrá un valor string con este aspecto:

nombre=Fernando&mensaje=Hola

Sin embargo, lo más cómodo para tratar este tipo de datos es por ejemplo convertir todo en un objeto json donde nombre y mensaje sean propiedades del mismo con los valores «Fernando» y «Hola» respectivamente. Algo como esto:

{nombre: "Fernando", mensaje: "Hola"}

Por eso, una vez recuperados los datos utilizamos el evento on() nuevamente pero con el valor ‘end’, osea cuando ha finalizado:

peticion.on('end', function(){
   var data_post_objeto = querystring.parse(data_post);
   mensajes_lista.push({nombre: data_post_objeto.nombre, mensaje: data_post_objeto.mensaje});
   respuesta.writeHead(200, {'Content-Type': 'text/html'});
   respuesta.end(mensajes.dibujarCodigoHtml(mensajes_lista));
});

Y convertimos los datos en un json gracias al método parse() del objeto querystring: y lo guardamos en la variable data_post_objeto.

var data_post_objeto = querystring.parse(data_post);

Y finalmente guardamos una nueva posición dentro del array mensajes_lista para mostrar todo por pantalla:

mensajes_lista.push({nombre: data_post_objeto.nombre, mensaje: data_post_objeto.mensaje});

Obviamente lo correcto sería guardar estos valores en una base de datos, ya que al reiniciar el servidor la variable mensajes_lista volverá a iniciarse con un array vacío, pero esto al menos nos sirve para saber como recuperar datos de una petición POST.

Para finalizar con esta publicación vamos a analizar algo, hasta acá todo bien, pero nuestro servidor así como está ahora se encuentra expuesto a ataques, ya que al permitirle al usuario enviar información desde campos de formulario da la posibilidad de que la petición sea muy pesada y cuelgue nuestra aplicación.

Para ello vamos a editar el código de index.js con lo siguiente:

var http = require('http');
var querystring = require('querystring');
var mensajes = require('./modulos/mensajes');
var mensajes_lista = new Array();
var data_post_maximo = 8 * 1024 * 1024;
http.createServer(function(peticion, respuesta){
   if(peticion.method == 'POST'){
      var data_post = '';
      peticion.on('data', function(data_cortada){
         data_post += data_cortada;
         if(data_post.length > data_post_maximo){
            this.pause();
            respuesta.writeHead(413);
            respuesta.end('Ha surgido un error y no puede continuarse.');
         }
      });
      peticion.on('end', function(){
         var data_post_objecto = querystring.parse(data_post);
         mensajes_lista.push({nombre: data_post_objecto.nombre, mensaje: data_post_objecto.mensaje});
         respuesta.writeHead(200, {'Content-Type': 'text/html'});
         respuesta.end(mensajes.dibujarCodigoHtml(mensajes_lista));
      });
   }else{
      respuesta.writeHead(200, {'Content-Type': 'text/html'});
      respuesta.end(mensajes.dibujarCodigoHtml(mensajes_lista));
   }
}).listen(3000, '127.0.0.1');
console.log('Servidor funcionando.');

En primer lugar creamos una variable donde vamos a definir la cantidad de memoria que nuestra aplicación va a soportar, en nuestro caso 8MB:

var data_post_maximo = 8 * 1024 * 1024;

Luego dentro de:

peticion.on('data', function(data_cortada){
   data_post += data_cortada;
   if(data_post.length > data_post_maximo){
      this.pause();
      respuesta.writeHead(413);
      respuesta.end('Ha surgido un error y no puede continuarse.');
   }
});

Vamos verificando si el string generado de los datos del post supera esos 8MB:

if(data_post.length > data_post_maximo){
   this.pause();
   respuesta.writeHead(413);
   respuesta.end('Ha surgido un error y no puede continuarse.');
}

De ser así, se cortará la ejecución del evento con .end() y devolverá por pantalla un mensaje de error tipo 413.

Ya podemos iniciar nuestro servidor y probarlo.

 

Anterior: Introducción a Node.js, parte 4: Enviar formularios por GET

Siguiente: Introducción a Node.js, parte 6: Envío de archivos

10 Replies to “Introducción a Node.js, parte 5: Enviar formularios por POST”

  1. Una chica me ha recomendado hoy tu tutorial y tengo que decir que realmente es fantástico!!
    Ahora a seguir buscando tutoriales más avanzados, pero lo más difícil que es conseguir la base… ya está hecho gracias a tí!!
    Muchas gracias!

    1. Gracias a vos, Sandra, por pasarte y firmar, y gracias a tu amiga también. Mirá, yo lo que voy publicando está basado en el curso del profesor Jesús Conde.

      Acá te dejo el link con los videotutoriales:

      http://www.youtube.com/watch?v=vnRGAsZdhx0

      Ahí Jesús explica varios temas, comienza desde cero, pero también explica cosas de Node como Express-Jade, conexiones con las base de datos, hacer un chat con programación bidireccional, etc. Te aconsejo que le pegues una hojeada.

      Saludos!

    1. No, porque el Html tenés que armarlo en forma dinámica.

      De todas formas entiendo lo que decís, para eso Express usa Jade.

  2. Hola muy bueno los tutoriales, los estoy haciendo, gracias por compartir información tan valiosa y tan bien explicada. Una cosita que no entiendo sobre este, una vez que tengo montado el servidor, como hago para enviarles datos por POST? ,porque con GET los escribis en la url, pero la verdad nose como hacerlo con POST.

    Muchas gracias y saludos

    1. Nikolai, cómo estás.

      El primer paso, es como se muestra en el ejemplo, el formulario desde el cuál vas a mandar una petición POST, debe tener el atributo:

      method=»post»

      Luego fijate la parte en donde yo puse:

      if(peticion.method == ‘POST’)

      En realidad lo que se hace ahí es ir recuperando la petición de a pedazos.

      Osea cuando vos en realidad mandás un formulario, lo que está haciendo es enviar algo como esto:

      «nombre=Juan&mensaje=hola»

      Ésa es la cadena que recupera el servidor.

      Nosotros recuperamos esa cadena de a trozos:

      peticion.on(‘data’, function(data_cortada){
      data_post += data_cortada;
      });

      Y la vamos concatenando en una variable String, que va a tener un aspecto similar a eso:

      «nombre=Juan&mensaje=hola»

      Luego mediante al objeto querystring, y el método parse():

      var data_post_objeto = querystring.parse(data_post);

      Convertimos ese String en un json.

      Osea que lo que llegó como:

      «nombre=Juan&mensaje=hola»

      Lo convertimos a este formato:

      {nombre: «Juan», mensaje: «Hola»}

      Y como cualquier Json, es fácil de manejar.

      Por favor, revisá nuevamente el posteo.

      Saludos!

Comments are closed.