0% encontró este documento útil (0 votos)
3 vistas13 páginas

Tema 1 - Parte II - Node - Js Como Servidor Web

Cargado por

loslibrosdejavi
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
3 vistas13 páginas

Tema 1 - Parte II - Node - Js Como Servidor Web

Cargado por

loslibrosdejavi
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 13

1. Introducción a Node.

js

Parte II – Node.js como servidor web

Despliegue de Aplicaciones Web

Nacho Iborra

IES San Vicente

Esta obra está licenciada bajo la Licencia Creative Commons


Atribución-NoComercial-CompartirIgual 4.0 Internacional. Para
ver una copia de esta licencia, visita
http://creativecommons.org/licenses/by-nc-sa/4.0/
Índice de contenidos
1. Introducción a Node.js..............................................................................1

1.Un primer servidor básico...............................................................................................3


1.1.Crear el servidor......................................................................................................3
1.2.Definir el "callback" para atender las peticiones.....................................................3
1.3.Accediendo a las cabeceras...................................................................................5
2.Enviar contenido HTML..................................................................................................6
2.1.Cargar páginas estáticas........................................................................................6
2.2.Uso de plantillas......................................................................................................7
3.Enrutamiento...................................................................................................................9
3.1.Procesar partes dinámicas en la ruta....................................................................11
3.2.Procesar los datos del formulario en la "query string"..........................................12

Despliegue de Aplicaciones Web – Introducción a Node.js 2.


1. Un primer servidor básico
A lo largo de este módulo, la principal utilidad que le daremos a Node.js es hacerlo
funcionar como un servidor web, que atenderá las peticiones de múltiples clientes,
enviando respuestas de diversos tipos: cargar una vista determinada, acceder a una
fuente de datos y enviar datos en formato JSON al cliente, recibir un archivo binario (por
ejemplo, una imagen) y subirlo a alguna carpeta del servidor, etc.
Notar que, a priori, el tener que programar nosotros desde cero un servidor web con
Node.js nos puede hacer pensar que nos va a llevar más trabajo la web que utilizando
otro lenguaje de servidor, como por ejemplo PHP, que ya se instala sobre un servidor web
completo como Apache. Sin embargo, veremos rápidamente que crear un servidor web
con Node.js no es nada complicado, y puede valer la pena.
Para poder llegar a todo esto, en esta sesión vamos a empezar con los fundamentos que
hacen que una aplicación Node.js pueda comportarse como un servidor web y atender
peticiones simples. Sobre esta base, iremos añadiendo cuestiones algo más elaboradas
como el enrutamiento, los eventos, o cómo atender peticiones de diversos tipos.

1.1. Crear el servidor


Vamos a crear un archivo llamado "servidor_basico.js" en nuestra carpeta de
"PruebasSimples". Para poder utilizar Node.js como servidor web, haremos uso del
módulo http que viene incluido por defecto en el núcleo de módulos de Node, y que
permite gestionar peticiones y respuestas HTTP. Así que un primer paso será incluir con
require dicho módulo:
const http = require('http');
El siguiente paso es crear una instancia del servidor:
http.createServer().listen(8080);
El parámetro del método listen indica por qué puerto quedará escuchando el servidor
web a la espera de que los clientes le pidan cosas. En este caso hemos especificado el
puerto 8080, ya que, en un entorno de pruebas, es posible que el puerto por defecto para
comunicaciones HTTP (puerto 80), esté ocupado, pero lo normal será dejar el servidor
escuchando en dicho puerto 80.
Si ejecutamos el archivo "servidor_basico.js" con estas dos instrucciones, y después
abrimos un navegador y accedemos a la URL http://localhost:8080, veremos que el
navegador se queda esperando una respuesta del servidor. Si cerramos el servidor
(cerramos la aplicación Node.js con Control+C, por ejemplo), el navegador mostrará un
mensaje de que no se puede acceder al sitio web. Es decir, mientras el servidor ha estado
en marcha, se ha establecido una conexión con él, pero no se han obtenido datos que
mostrar.

1.2. Definir el "callback" para atender las peticiones


Lo que nos ha ocurrido en el punto anterior parece obvio si analizamos el (poco) código
que hemos escrito. Nos hemos limitado a crear un servidor y decirle que se quede
escuchando peticiones en el puerto 8080. Pero una vez obtenga una conexión... ¿qué?

Despliegue de Aplicaciones Web – Introducción a Node.js 3.


Lo siguiente que debemos hacer es definir un callback, una función que se llamará cada
vez que se acepte una conexión, y que contendrá el código a ejecutar para atenderla. En
el caso del servidor HTTP, la función debe tener dos parámetros: un objeto con los datos
de la petición (típicamente se le suele llamar request, "petición" en inglés), y otro que
contendrá los datos de la respuesta que enviará el servidor (típicamente se le suele llamar
response, "respuesta" en inglés).
El esqueleto básico de nuestro callback quedaría así:
var atenderPeticion = (request, response) => {
// Código para atender la petición
}
Hemos empleado una arrow function, pero también podemos emplear una función
tradicional o una función anónima si preferimos. Dentro del código de la misma, lo que
haremos será procesar la petición y emitir una respuesta acorde a la misma. Para
empezar, vamos a ignorar los datos de la petición, y a emitir una respuesta de bienvenida,
sea quien sea el origen.
var atenderPeticion = (request, response) => {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Bienvenido/a");
response.end();
}
Analicemos un poco el código que hemos generado:
• La primera línea envía un código de estado HTTP (200, es decir que todo ha ido
bien), y unas cabeceras de respuesta. En esta caso sólo se envía una cabecera
Content-Type que indica que lo que se va a enviar es texto plano (tipo MIME). Para
enviar documentos web, emplearíamos text/html como tipo MIME.
• Después, generamos el contenido de dicho documento. En este caso, un simple
texto "Bienvenido/a".
• Para terminar, finalizamos la respuesta.
Nos falta, por último, enlazar esta función callback con el servidor que está escuchando
en el puerto 8080. Para ello, pasamos esta función como parámetro al método
createServer:
http.createServer(atenderPeticion).listen(8080);
Si ahora ejecutamos el servidor Node y conectamos a la URL anterior desde un
navegador, obtendremos el mensaje de bienvenida como respuesta:

1.2.1. Otras alternativas de código


Como hemos comentado, existen otras formas diferentes de implementar este ejemplo.
Podríamos haber definido una función anónima en lugar de una arrow function:

Despliegue de Aplicaciones Web – Introducción a Node.js 4.


var atenderPeticion = function (request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Bienvenido/a");
response.end();
}
E incluso podríamos haber definido la función anónima como parámetro de la llamada a
createServer:
http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Bienvenido/a");
response.end();
}).listen(8080);
La forma de llegar al objetivo es indiferente, siempre que se ajuste a los estándares de la
empresa en la que estamos desarrollando, y tenga cierta homogeneidad, es decir, que no
utilicemos cada vez una forma diferente por capricho (recuerda que las arrow functions no
pueden utilizarse en ciertas circunstancias, y en ese caso habría que optar por otras
opciones).
A lo largo de este módulo, emplearemos arrow functions cuando nos sea posible, ya que
nos permite un código más compacto e igualmente legible.

1.3. Accediendo a las cabeceras


En el ejemplo anterior ya hemos visto que podemos acceder y establecer las cabeceras
de la respuesta mediante el método writeHead del propio objeto respuesta que se le
pasa como parámetro al callback que atiende peticiones.
Para acceder a las cabeceras de petición (estas cabeceras son de lectura, no pueden
modificarse), se tiene disponible un objeto llamado headers dentro del objeto de petición
(request en el ejemplo anterior). El siguiente ejemplo saluda al usuario y le indica qué
navegador está usando (cabecera "user-agent"):
var atenderPeticion = (request, response) => {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Bienvenido/a\n");
response.write("Tienes este navegador: " +
request.headers['user-agent']);
response.end();
}
Ejercicio 1
Crea una carpeta llamada "Tema1_SaludoNavegador" en tu carpeta de ejercicios. Dentro,
crea un servidor web que atienda peticiones y, para cada una, obtenga la cabecera "user-
agent" que muestra los datos del navegador, y detecte si está usando Google Chrome o
no. En caso afirmativo, deberá mostrar el mensaje "Utilizas Google Chrome", y en caso
negativo mostrará "Utilizas un navegador no reconocido".

Despliegue de Aplicaciones Web – Introducción a Node.js 5.


2. Enviar contenido HTML
Ahora que ya sabemos construir un servidor que atiende peticiones básicas y responde
con texto plano, veamos qué opciones elementales tenemos para enviar contenido HTML
al cliente.

2.1. Cargar páginas estáticas


Si queremos generar contenido HTML como respuesta, puede ser muy incómodo
generarlo a base de instrucciones write como la que hemos utilizado antes para saludar
al usuario. En su lugar, lo más conveniente es tener el contenido en documentos HTML, y
cargar y enviar el que se necesite.
Vamos a crear una carpeta llamada "PruebaServidorHTML" en nuestra carpeta de
"Pruebas". Dentro, vamos a crear un archivo llamado "index.html" con este contenido de
una página básica:
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>Bienvenido/a</h1>
</body>
</html>
Además, vamos a crear un archivo "servidor.js" con nuestro servidor Node. Para poder
leer el documento HTML anterior necesitaremos cargar la librería fs, y después
podremos enviar el contenido leído directamente con una instrucción write como la del
ejemplo anterior. El código quedaría así:
const http = require('http');
const fs = require('fs');

var atenderPeticion = (request, response) => {


response.writeHead(200, {"Content-Type": "text/html"});
var contenido = fs.readFileSync('./index.html', 'utf8');
response.write(contenido);
response.end();
}

http.createServer(atenderPeticion).listen(8080);
Notar que hay algunos cambios con respecto a la versión anterior de servidor:
• Incluimos la librería fs (junto a http)
• Cambiamos el tipo de contenido en la cabecera de respuesta ("Content-Type") a un
contenido HTML ("text/html") en lugar de texto plano.
• Cargamos el fichero con fs.readFileSync en una variable, que almacenará su
contenido (suponemos que el fichero está codificado en UTF-8). Esa variable es la
que luego volcamos en la respuesta con write. Notar también que hemos

Despliegue de Aplicaciones Web – Introducción a Node.js 6.


utilizado un método síncrono (readFileSync), que bloquea el programa hasta
que cargue el fichero. Lo hemos hecho así porque hasta que no cargue el fichero
no podemos enviarlo como respuesta.

2.2. Uso de plantillas


La carga de páginas estáticas HTML como respuesta a peticiones tiene un ámbito de uso
muy limitado. Normalmente casi todas las páginas que visitamos tienen algún tipo de
contenido dinámico: algunas tienen un mensaje de saludo personalizado para el usuario
que se ha logueado, otras cargan unas u otras preferencias, etc.
Podemos definir plantillas en nuestros documentos HTML para luego sustituir la parte
dinámica de su contenido por lo que necesitemos en cada caso. Por ejemplo, podemos
dejar nuestro documento "index.html" anterior así:
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>Bienvenido/a</h1>
<p>Tu navegador es: {navegador}</p>
</body>
</html>
En este caso, hemos definido un placeholder para indicar qué navegador está usando el
usuario. Lo sabremos en el servidor cuando leamos la cabecera "user-agent". Así, en el
código del servidor, sólo tenemos que leer el contenido del documento HTML, y
reemplazar {navegador} por el contenido de dicha cabecera. Quedará así:
const http = require('http');
const fs = require('fs');

var atenderPeticion = (request, response) => {


response.writeHead(200, {"Content-Type": "text/html"});
var contenido = fs.readFileSync('./index.html', 'utf8');
var navegador = request.headers['user-agent'];
contenido = contenido.replace('{navegador}', navegador);
response.write(contenido);
response.end();
}

http.createServer(atenderPeticion).listen(8080);
Notar que lo que hacemos es almacenar el navegador de la cabecera en una variable, y
luego sustituir (replace) el texto que hemos dejado en la plantilla ('{navegador}') por
el navegador que hemos detectado, antes de volcar el contenido en la respuesta.

Despliegue de Aplicaciones Web – Introducción a Node.js 7.


Obviamente, hacer algo así para una plantilla compleja, con muchas cosas a sustituir, e
incluso con partes del documento que mostrar u ocultar dependiendo de determinadas
condiciones, puede ser algo tedioso de programar. Por fortuna, existen motores de
plantillas que nos pueden facilitar mucho el trabajo, aunque los veremos más adelante.
Ejercicio 2
Crea una carpeta llamada "Tema1_PlantillaNavegador" en tu carpeta de "Ejercicios".
Vamos a hacer una variante del ejercicio anterior, en la que generaremos el contenido
HTML establecido en una plantilla llamada "saludo.html" (dentro de la carpeta de nuestro
ejercicio):
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>Página de saludo</h1>
<p>{saludo}</p>
</body>
</html>
Nuestro servidor deberá leer esta plantilla para cada petición, y sustituir el texto
'{saludo}' por el mismo texto identificativo del navegador que has empleado en el
ejercicio anterior ("Utilizas Google Chrome" o "Utilizas un navegador no reconocido",
respectivamente).

Despliegue de Aplicaciones Web – Introducción a Node.js 8.


3. Enrutamiento
El servidor básico que hemos desarrollado hasta ahora está bien como punto de partida,
pero es poco práctico. Si escribimos cualquiera de estas URLs, obtendremos el mismo
contenido:
• http://localhost:8080
• http://localhost:8080/loquesea
• http://localhost:8080/una_pagina.html
Este resultado nos puede sorprender. La página "una_pagina.html" ni siquiera existe, y sin
embargo obtenemos una respuesta. Pero miremos el código de nuestro servidor: escucha
por el puerto 8080, y para cualquier petición que le llegue (pidiendo el contenido que sea)
le estamos enviando la misma respuesta (el mensaje de bienvenida).
No vamos a generar siempre el mismo contenido para todas las peticiones que nos
lleguen en una web real, sino que lo normal será analizar la petición, ver de qué tipo es y
qué recurso u operación solicita, y en función de eso generar un tipo de respuesta u otra.
Como hemos comentado anteriormente, las respuestas pueden ser de lo más variopintas:
desde devolver un simple contenido HTML (que puede ser un documento u otro, según lo
que pida el cliente), hasta conectar con una base de datos, obtener un conjunto de
registros y devolverlos en formato JSON al cliente, o bien tomar datos de la petición para
almacenar alguna información (un archivo, un nuevo registro en la base de datos, etc.).
Lo que vamos a ver en este apartado es un mecanismo básico para identificar información
de la petición y, en función de la misma, redirigir hacia una respuesta u otra. Es lo que se
denomina enrutamiento (routing), analizar la petición HTTP y generar una u otra
respuesta en función de la misma.
Más adelante veremos mecanismos más refinados de analizar la petición, pero de
momento vamos a centrarnos en la propiedad "url" del objeto de la petición (request).
Esta propiedad almacena la parte de la URL que representa el recurso solicitado (es decir,
lo que va a continuación del nombre del servidor y puerto). Podríamos, por ejemplo,
distinguir entre una página de bienvenida y otra de despedida, además de la página
principal, de este modo:
var atenderPeticion = (request, response) => {
response.writeHead(200, {"Content-Type": "text/plain"});

if (request.url === '/') {


response.write("Página principal");
} else if (request.url == '/bienvenida') {
response.write("Bienvenido/a");
} else if (request.url == '/despedida') {
response.write("Hasta pronto");
}

response.end();
}

Despliegue de Aplicaciones Web – Introducción a Node.js 9.


Vamos a añadir este código (junto con el resto necesario para crear el servidor) en un
archivo llamado "servidor_enrutamiento.js" en nuestra carpeta de "PruebasSimples".
Después, pongámoslo en marcha e intentemos acceder a estas URLs, y observemos qué
pasa en cada caso:
• http://localhost:8080/bienvenida
• http://localhost:8080/despedida
• http://localhost:8080
• http://localhost:8080/loquesea
Notar que en el caso de las tres primeras, nos muestra los textos de "Bienvenido/a",
"Hasta pronto" y "Página principal", respectivamente. En el caso de la última URL, no es
ninguna de las tres que tenemos preparadas, por lo que genera un contenido en blanco.
Podríamos modificar este comportamiento para mostrar una página de error si
quisiéramos. No es nada difícil con lo que hemos visto hasta ahora.
Nuevamente, este mecanismo para enrutar nos resulta insuficiente para hacer frente a
una web real. Existen muchas URLs con partes dinámicas. Por ejemplo, podríamos
querer cargar la ficha de un libro a partir de su código, y que el código sea parte de la
URL, de esta forma:
http://mipaginadelibros.com/fichaLibro/1234
Necesitamos un mecanismo que nos permita procesar las partes de la URL, y emitir una
respuesta genérica (la ficha del libro) para todo el que acceda a '/fichalibro', y aparte,
rellenar la ficha con un contenido que dependa del código del libro que viene a
continuación. Podríamos procesar la URL nosotros mismos, emplear expresiones
regulares para detectar patrones, etc. Pero, afortunadamente, existen frameworks que
nos facilitan mucho esta tarea, así como la de generación de plantillas comentada
anteriormente. Los veremos más adelante.
Ejercicio 3
Crea una carpeta llamada "Tema1_EnrutamientoBasico" en tu carpeta de ejercicios.
Dentro, deberás definir un servidor que identifique y dé una respuesta diferente para cada
una de estas rutas:
• /usuario : mostrará el login del usuario que entró al sistema operativo (usando el
módulo "os"), como texto plano
• /carpeta : mostrará un listado de los archivos y carpetas contenido en la carpeta
raíz de la aplicación (usando el módulo "fs"), como texto plano, con un archivo o
carpeta por línea
• / : mostrará una página HTML predefinida llamada "index.html", con este contenido:
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>Página de bienvenida</h1>
<ul>
<li><a href="/usuario">Ver usuario del sistema</a></li>
<li><a href="/carpeta">Ver carpeta de la aplicación</a></li>
</ul>

Despliegue de Aplicaciones Web – Introducción a Node.js 10.


</body>
</html>
Notar que el contenido de la página contiene dos enlaces para acceder a las dos
rutas anteriores.
• Cualquier otra ruta deberá mostrar una página de error como la siguiente (busca
alguna imagen en Internet que te sirva para construir una página similar, y decide
cómo construirla y mostrarla desde el servidor).

3.1. Procesar partes dinámicas en la ruta


Comentábamos que va a ser habitual encontrarnos con partes de la ruta que sean
dinámicas, como por ejemplo el id del libro que queremos ver:
http://mipaginadelibros.com/fichaLibro/1234
Aunque veremos más adelante otros mecanismos para extraer esta información, vamos a
proporcionar ahora un mecanismo algo rudimentario para poder empezar a hacer tareas
más versátiles. Para ello, vamos a obtener la propiedad url de la petición, como en el
ejemplo anterior, y vamos a trocearla con la función split. De esta forma podríamos
obtener cuál es el código del libro que queremos ver:
if (request.url.startsWith('/fichaLibro')) {
var partes = request.url.split("/");
response.write("El código del libro es " + partes[2]);
}

Despliegue de Aplicaciones Web – Introducción a Node.js 11.


Lo que hacemos es utilizar el método startsWith para no comparar literalmente la URL,
sino sólo asegurarnos de que empieza por el patrón que nos interesa ("/fichaLibro" en
este caso). Después, se trocea la URL usando la barra como separador "/", y nos
quedamos con el tercer elemento del array de trozos, ya que el primer elemento sería una
cadena vacía (lo que hay antes de la primera barra), y el segundo elemento sería
"fichaLibro". Podemos añadir este ejemplo como un caso más de nuestro servidor de
pruebas "servidor_enrutamiento.js", en la carpeta de "PruebasSimples".
Ejercicio 4
Crea una carpeta llamada "Tema1_EnrutamientoEdad" que deberá procesar una URL con
esta estructura:
http://servidor/saludo/nombre/edad
Todo lo que llegue a "/saludo" deberá procesarse, y a continuación extraer el nombre del
usuario y la edad. El servidor deberá saludar al usuario por su nombre, e indicarle si es o
no mayor de edad. Por ejemplo:
http://localhost:8080/saludo/nacho/39
=> Hola nacho, eres mayor de edad
http://localhost:8080/saludo/pepe/15
=> Hola pepe, no eres mayor de edad

3.2. Procesar los datos del formulario en la "query string"


En ocasiones es posible que los datos dinámicos de la petición (como por ejemplo, el id
del libro a mostrar) no formen parte de la ruta, sino de lo que se conocen como "datos del
formulario", o en inglés "query string". Esto datos se pasan a continuación de la ruta, en el
caso de peticiones GET. Así, para mostrar la ficha de un libro, pasaríamos el id del libro de
esta otra forma:
http://mipaginadelibros.com/fichaLibro?id=1234
Se pueden enlazar tantos datos como se quieran (hasta un límite de longitud de cadena
que depende de varios factores), separados por el símbolo &. Por ejemplo:
http://miservidor.com?param1=valor1&param2=valor2&param3=valor3
En el caso de tener URLs construidas de esta forma, podemos utilizar el módulo url que
viene en el núcleo de Node.js, y en concreto su método parse para procesar la URL y
extraer la query string, que podemos consultar en la propiedad query. Después,
podemos acceder a cada dato por separado. Por ejemplo, para extrar el id del libro en la
URL anterior, podríamos hacer esto:
const url = require('url');
...
var parametros = url.parse(request.url, true).query;
var id = parametros.id;
Ejercicio 5
Modifica el ejercicio anterior añadiendo un servidor alternativo que envíe el nombre y la
edad del usuario como datos del formulario, de esta forma:
http://servidor/saludo?nombre=xxx&edad=yyy

Despliegue de Aplicaciones Web – Introducción a Node.js 12.


Para procesar esta URL, emplea el módulo url como se ha explicado en el ejemplo
anterior, y genera la misma respuesta que en el ejercicio previo.

Despliegue de Aplicaciones Web – Introducción a Node.js 13.

También podría gustarte