Archivo de la etiqueta: servidor

Crear un servidor web con Node.js (II)

En el anterior capítulo nos quedamos con el servidor Node montado y corriendo. Lo próximo es construir una aplicación más compleja que responda a varias URLs, para ver en movimiento algo de lo que sería REST. Evidentemente, debemos examinar la petición HTTP, extrayendo de ella la URL pedida y, ocasionalmente, sus parámetros GET/POST.

La idea es que para procesar las peticiones necesitamos una especie de router que, dependiendo de la URL, mapee a los distintos manejadores, y en un rato veremos el cómo. En este punto hace falta aclarar un pequeño detalle:

Si comparamos Node con, por ejemplo, un Apache+PHP, hay una diferencia principal: el código PHP contiene la lógica, accesos a base de datos, etc.; es decir, implementa la aplicación, pero es Apache quien se encarga de servirla y gestionar las peticiones. Node realiza las funciones de ambos, no sólo implementamos la aplicación sino también todo el servidor, de forma que la aplicación web y su servidor web son esencialmente lo mismo.

Callbacks y funciones anónimas

Bien, ya vimos la función principal en nuestro hello.js, que crea el servidor y escucha peticiones en el puerto indicado. Al crear el servidor le estamos pasando una función como parámetro, lo cual se puede hacer en JavaScript incluso sin crear anteriormente la función. Es decir, se puede asignar una función a una variable y después pasar esta como parámetro, o bien definir la función en el mismo parámetro y por tanto no hay que darle un nombre (función anónima).

Este tipo de comportamiento se debe a la naturaleza de Node.js y a que trabaja orientado al evento. De esta forma, pasando una función al método que crea el servidor, cada vez que se reciba una petición, esta función será llamada (callback). Así que manipulamos ahí mismo la petición entrante, justo donde se captura el evento.

La estructura de la URL

Por otra parte, a la función que responde al evento (manejador) se le pasan dos objetos, request y response, con cuyas propiedades podemos obtener los detalles de la petición y procesarla adecuadamente.

Repasemos por un momento la estructura de las URLs y las partes que nos pueden interesar. En esencia, una URL puede tener unas cuantas de estas cosas (algunas de ellas están siempre, aunque no las veamos en el navegador, como las meigas):

URL parts

Brevemente:

  • Protocolo: normalmente HTTP, pero también HTTPS, FTP, etc.
  • Host/Hostname: dominio, es decir, nombre o dirección IP de la máquina.
  • Puerto: puerto de red en el que escucha (por defecto 80 en HTTP).
  • Path: ruta en la que se localiza el recurso.
  • Query: parámetros de la petición: pares de variable=valor.

Obviamente, las partes importantes aquí son el path y la query: queremos saber a qué recurso se ha accedido, y si vienen datos con ello. Los obtenemos de la siguiente manera (usando los módulos internos url y querystring):

var url = require(‘url’);
var querystring = require(‘querystring’);

// Obtener el path o la query como cadena
var path = url.parse(request.url).pathname;  // “/hola”
var query = url.parse(request.url).query;  // “nombre=Pepito&apellido=Pérez”
// Obtener el objeto JSON a partir de la cadena query
var params = querystring.parse(query);  // { nombre: Pepito, apellido: Pérez }

A través del objeto request también podemos obtener otras cosas interesantes, como protocolo y versión, método, cabeceras…

Módulos: require y exports

Para dotar a nuestra aplicación de cierta organización, podemos separar todo el código en módulos. Esencialmente, un módulo es un fichero que agrupa ciertas funcionalidades, y que se puede usar posteriormente desde otro fichero.

Vemos en los ejemplos algunas líneas con require. Dado que ‘http’, ‘url’ o ‘querystring’ son módulos (internos de Node.js en este caso), require carga las funcionalidades que dichos módulos proporcionan (exportan).

Ahora nos queda crear nuestros propios módulos, y despues utilizarlos. Dentro de un módulo, podemos elegir qué partes queremos exportar, ya que todo lo que haya dentro es por defecto privado (variables, funciones, clases…). Y de hecho, la palabra que se usa para ello es exports.

Lo explican genial aquí, por lo que me limito a decir que lo haríamos de una de las dos formas:

a)     Exportando los componentes por separado:

var num = 35;
var sumar = function(a, b) {
    return a+b;
}
module.exports.num = num;
module.exports.sumar = sumar;
--------------------------------
var utils = require(‘./modulo);
var x = utils.num + 2;
var res = utils.sumar (4,9);

b)     Exportando todo en una función:

var miClase = function(param1, param2) {
   this.param1 = param1;
   this.param2 = param2;
}
module.exports = miClase;
--------------------------------
var clase = require(‘./miClase’);
var obj = new clase();
// O también:
var obj = new require(‘./miClase’)();

Mezclar y agitar

Muy bien, ya tenemos todos los ingredientes: callbacks y funciones anónimas, partes interesantes de la URL y nuestros propios módulos.

Ya podemos hacernos nuestro router casero, y poder decirle hola y adiós al usuario (un ejemplo muy básico para entender cómo se mapean las peticiones).

Para que no haya confusión, voy a renombrar mi hello.js a app.js (nombre más coherente), y voy a crear también router.js, que será usado en la aplicación principal.

function route(pathname, query) {
    switch (pathname) {
        case "/hola":
            return "Hello " + query["nombre"] + " " + query["apellido"]
        case "/adios":
            return "Bye bye " + query["nombre"] + " " + query["apellido"]
        default:
            return "Este recurso no existe!"
    }
}
exports.route = route;
var http = require('http');
var url = require('url');
var querystring = require('querystring');
var router = require('./router');

http.createServer(function (request, response) {
    res.writeHead(200, {"Content-Type'": "text/html"});

    var pathname = url.parse(req.url).pathname;
    var query = url.parse(req.url).query;
    var params = querystring.parse(query);

    var response = router.route(pathname, params);
    res.write(response);
    res.end();
}).listen(5555);

Claro que se podría hacer algo más elaborado, como tener en cuenta el método (GET/POST) y hacer cosas diferentes con uno y otro, pasarle al router también el objeto response y devolver una página 404 para los recursos que no existan, o bien cambiar el switch y organizar los recursos pedidos de otra manera…

Para todo esto existe una librería que veremos el próximo día: Expressjs 🙂

Saludos!

Deja un comentario

Archivado bajo Tecnologías, Tutoriales

Crear un servidor web con Node.js (I)

Ya vimos aquí en que consistía la arquitectura REST; ahora es el turno de poner en práctica ese esquema implementando nuestro propio servidor web, y el lenguaje afortunado va a ser Javascript.

¿Cómor? ¿Javascript en el servidor?

¡Si yo creía que se utilizaba en el cliente para hacer mi web más interactiva! Modificar sobre la marcha la estructura del documento, alterar su apariencia, gestionar eventos…

Pues sí, pero además se puede construir con él un servidor aprovechando todas sus ventajas. Claro que la manera de desarrollar con Javascript en el servidor es diferente a cómo lo usamos en el navegador.

En este sentido, Javascript es un lenguaje de programación “completo” como cualquier otro, y podemos hacer con él las mismas cosas que con los demás. Si quieres conocerlo y exprimirlo, te recomiendo que eches un vistazo a los muchos manuales y libros que pululan por Internet, como este.

Javascript es un lenguaje idóneo para programación orientada a eventos: permite funciones anónimas, la sintaxis es similar a muchos otros lenguajes, y los callbacks que se llaman al dispararse los eventos se pueden escribir en el mismo punto en el que se captura el evento. Sencillo de implementar y de mantener. Esperar un evento, devolver la llamada, et voilà.

Node.js

El problema con muchos lenguajes de servidor (como PHP), es que cada conexión genera un nuevo hilo, con el consiguiente consumo de recursos: procesador, memoria… Por lo tanto, un sistema con una cantidad limitada de RAM tiene un máximo teórico de conexiones concurrentes. Si la base de datos de clientes crece mucho, habrá que añadir más y más servidores, lo que supone más y más costes: los propios servidores, lógica de negocio, costes laborales, problemas técnicos potenciales, etc.

Conclusión: número limitado de conexiones concurrentes = gran cuello de botella.

Aquí es donde surge Node.js, que resuelve este problema cambiando la forma en la que se realizan estas conexiones. Por cada nueva conexión, en lugar de generarse un nuevo hilo de SO, se dispara un evento en el motor de ejecución.

Node es un intérprete Javascript que corre en el lado del servidor, es decir, fuera del navegador. Permite construir fácilmente aplicaciones de red muy rápidas y altamente escalables, y manejar miles de conexiones simultáneas en la misma máquina física.

Para ello, utiliza un modelo dirigido por eventos con E/S no bloqueante, lo que lo hace ligero y eficiente, perfecto para aplicaciones de uso intensivo de datos en tiempo real.

Lo que hace Node es interpretar y ejecutar el código Javascript, haciendo uso de la máquina virtual V8 de Google, el mismo entorno de ejecución para Javascript que utiliza Google Chrome.

Además, cuenta con una gran colección de módulos con diferentes utilidades, de modo que se simplifican muchas tareas.

Por lo tanto, Node es dos cosas: un entorno de ejecución y una librería.

Los módulos sirven para expandir la funcionalidad de Node. Son tan importantes que se han convertido en una parte esencial del producto completo. Aquí entra en juego npm (Node Package Manager), el gestor de paquetes, que es una forma integrada de instalar y administrar los módulos y sus dependencias. Un extra es que uno mismo puede publicar sus propios módulos y contribuir así a la comunidad de desarrolladores.

Según todo esto que hemos visto, Node está diseñado para situaciones en las que esperamos una gran cantidad de tráfico y donde la lógica y procesamiento requeridos no sean necesariamente grandes.

Instalación y actualización

En primer lugar, debemos instalar Node.js siguiendo estas instrucciones. Allí se explican los prerrequisitos, problemas comunes y la forma de compilarlo (build) en los distintos sistemas operativos; aunque la manera más sencilla es instalarlo directamente sin compilarlo (como yo voy a hacer), bien de forma automática o bien manual.

Yo estoy utilizando Windows, por lo que las instrucciones siguientes son para instalarlo en este SO, pero si estáis en Linux/UNIX o Mac podéis hacer el build como se explica en dicha web, o instalarlo siguiendo las instrucciones del final de la misma, es decir, mediante el gestor de paquetes de cada SO o descargando los binarios correspondientes para cada plataforma.

Se recomienda realizar la instalación manual para atajar los problemas de hacerlo automáticamente. Los pasos a seguir son sencillísimos:

  • Crear un directorio vacío y añadirlo a la variable PATH del sistema.
  • Descargar la última versión del .exe de Node.js correspondiente (32 o 64 bits) en ese directorio.
  • Descargar la última versión del .zip de npm (el gestor de paquetes de Node) y descomprimirlo en el mismo directorio.

Si, de todas formas, queremos hacerlo de forma automática, basta con descargar la última versión del paquete .msi (instalador para Windows), y con él se instalará tanto Node.js como npm.

De esta forma y gracias al PATH ya podremos ejecutar scripts (node scriptname.js) e instalar módulos (npm install modulename) en cualquier directorio (no olvidéis abrir un terminal y probar ambos comandos ;)).

Para actualizar el propio Node o npm, basta con hacer lo siguiente:

  • Descargar la última versión del .exe de Node.js correspondiente (32 o 64 bits), igual que el segundo paso anterior, y reemplazar el viejo .exe con él.
  • Para npm, ejecutar el comando: npm update npm –g

¡Hello World!

¡Por fin! Ya tenemos todo instalado y configurado, y vamos a probarlo escribiendo el clásico saludo de bienvenida en cualquier lenguaje.

Abrid vuestro editor favorito (desde Bonus4Code os recomendamos Sublime) y cread un archivo de extensión .js. El mío va a ser hello.js.

Dentro podríamos escribir un simple comando que escribiese ‘Hola’ por pantalla (en stdout) al ser ejecutado, pero como hablamos de webs, vamos a crear el servidor y que nos lo devuelva mejor en el navegador, ¿no? 🙂

var http = require('http');

http.createServer(function (req, res) {
    res.writeHead(200, {“Content-Type': 'text/html”});
    res.write(“Hello World”);
    res.end();
}).listen(5555);

console.log('Servidor haciendo algo en: http://127.0.0.1:5555/');

Guardamos, abrimos un terminal y ya sabemos:

node hello.js

Debería mostrarse el mensaje de log, y el servidor ya está corriendo. Así que sólo queda ir al navegador, entrar en http://localhost:5555 y ver nuestro Hello World en acción (eso sí, muy feíto el pobre y sin ningún estilo…).

Más en próximas entregas 😀

Deja un comentario

Archivado bajo Tecnologías, Tutoriales