En la última publicación vimos cómo instalar Node.js, y también habíamos dicho que éste es un lenguaje de programación orientado a eventos. Y también a aprendimos a crear nuestro primer servidor Node.js mediante el uso del módulo http. Este objeto mediante el evento .createServer() escuchará y ejecutará una función cada vez que un cliente se conecte al servidor:
var http = require('http');
http.createServer(function(peticion, respuesta){
var codigo_html = '<html> <head> <title> Ejemplo de hola mundo </title> </head> <body> Hola mundo </body> </html>';
respuesta.writeHead(200, 'text/html');
respuesta.end(codigo_html);
}).listen(3000, '127.0.0.1');
console.log('El servidor esta funcionando correctamente en https://localhost:3000/');
Al iniciar nuestro servidor podemos acceder desde nuestro localhost a la dirección:
https://localhost:3000/
Al ingresar a esta url el servidor nos devolverá una respuesta html para que el navegador nos muestre la página, nada nuevo.
Sin embargo nuestro servidor aun no es capaz de detectar la petición según la url por la que ha accedido el visitante. Con esto quiero decir que si ingresamos a:
https://localhost:3000/
O:
https://localhost:3000/info.html
El servidor siempre nos devolverá la misma respuesta.
Para ello nosotros debemos detectar el path o url a la que se está accediendo e indicarle a nuestro servidor la respuesta a devolver.
Entonces vamos a crear una carpeta en nuestros proyectos de la carpeta node.js llamada estatica.
Dentro crearemos un archivo llamado index.js y a la misma altura un directorio llamado contenido. Y dentro de este último vamos a crear dos archivos: index.html e info.html y a la misma altura de estos una carpeta llamada css y dentro de ésta última, un archivo de nombre style.css.
Bien, ahora iremos a la raíz de nuestro proyecto al archivo index.js y lo editaremos con el siguiente código:
var http = require('http');
var url = require('url');
http.createServer(function(peticion, respuesta){
var path_nombre = url.parse(peticion.url).pathname;
respuesta.writeHead(200);
respuesta.end('El path es: ' + path_nombre);
}).listen(3000, '127.0.0.1');
console.log('El servidor esta funcionando correctamente en https://localhost:3000/');
Como se ve en el ejemplo, incluimos un nuevo módulo llamado url:
var url = require('url');
Éste nos devolverá un objeto con información justamente de la url.
Luego dentro con .createServer(), evento que se disparará cada vez que llegue una nueva petición al navegador, recuperamos el path donde está accediendo el usuario:
var path_nombre = url.parse(peticion.url).pathname;
Entonces si por ejemplo ahora accedemos a:
https://localhost:3000/
Esta variable path_nombre tendrá el valor de ‘/’, y si accedemos a:
https://localhost:3000/info.html
Entonces el valor será: ‘/info.html’
De esta manera entonces nosotros ya tenemos la información suficiente para que cuando el usuario ingrese a nuestra aplicación, buscar el archivo correspondiente y devolverle su contenido al navegador.
Entonces vamos a volver a nuestro archivo index.js y vamos a editarlo nuevamente con el siguiente código:
var http = require('http');
var url = require('url');
var fs = require('fs');
http.createServer(function(peticion, respuesta){
var path_nombre = (url.parse(peticion.url).pathname == '/') ? '/index.html' : url.parse(peticion.url).pathname;
var ruta_a_archivo = 'contenido/' + path_nombre;
fs.exists(ruta_a_archivo, function(existe){
if(existe){
fs.readFile(ruta_a_archivo, function(error, contenido_archivo){
if(error){
respuesta.writeHead(500, 'text/plain');
respuesta.end('Error interno.');
}else{
respuesta.writeHead(200, {'Content-Type': 'text/html'});
respuesta.end(contenido_archivo);
}
});
}else{
respuesta.writeHead(404, 'text/plain');
respuesta.end('Error 404. El enlace no existe o ha dejado de existir.');
}
});
}).listen(3000, '127.0.0.1');
console.log('El servidor esta funcionando correctamente en https://localhost:3000/');
Bien, en primer lugar incluimos el módulo:
var fs = require('fs');
El cual nos permitirá trabajar con archivos.
Con respecto a la variable path_nombre, haremos un pequeño cambio con respecto al código a como estaba antes:
var path_nombre = (url.parse(peticion.url).pathname == '/') ? '/index.html' : url.parse(peticion.url).pathname;
Esta variable preguntará si el pathname es ‘/’ lo que significa que el visitante está en la página principal, en este caso forzaremos a que path_nombre sea ‘/index.html’, que es el archivo principal. De lo contrario guardará el pathname así como lo encuentra.
Luego guardamos una variable con la ruta al archivo que tendremos que leer:
var ruta_a_archivo = 'contenido/' + path_nombre;
Recordar que en la carpeta contenido se encuentran los archivos .html.
Vamos a buscar ése, ya que la url puede ser incorrecta, y apuntar a un archivo que no existe:
fs.exists(ruta_a_archivo, function(existe){
if(existe){
fs.readFile(ruta_a_archivo, function(error, contenido_archivo){
if(error){
respuesta.writeHead(500, 'text/plain');
respuesta.end('Error interno.');
}else{
respuesta.writeHead(200, {'Content-Type': 'text/html'});
respuesta.end(contenido_archivo);
}
});
}else{
respuesta.writeHead(404, 'text/plain');
respuesta.end('Error 404. El enlace no existe o ha dejado de existir.');
}
});
El evento .exists() nos permitirá buscar un archivo, recibirá dos parámetros, la ubicación física del mismo y una función que recibirá un parámetro que será true si encontró el archivo y false, si no fue así. En este último caso devolveremos al cliente un error 404, que significa que la página no existe:
respuesta.writeHead(404, 'text/plain');
respuesta.end('Error 404. El enlace no existe o ha dejado de existir.');
Si en cambio el archivo sí existe, osea que entra por el otro lado del if, el lado verdadero, entonces intentará leer el mismo mediante el evento .readFile(). Éste recibirá dos parámetros, el archivo y una función que a su vez recibirá dos parámetro, el primero será si se ha producido un error al leer el archivo y el segundo es el contenido del archivo.
Si surgió algún error al intentar leer el archivo le devolverá al cliente un error 500, que es un error interno del servidor:
respuesta.writeHead(500);
respuesta.end('Error interno.');
Si en cambio el archivo pudo leerse correctamente, por fin, devolverá el contenido del archivo .html:
respuesta.writeHead(200, {'Content-Type': 'text/html'});
respuesta.end(contenido_archivo);
Finalmente vamos a editar los dos archivo .html que se encuentran dentro de la carpeta contenido:
index.html:
<!DOCTYPE>
<html>
<head>
<title> Ejemplo de Node.js </title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<h1> Index </h1>
<ul>
<li> <a href="/index.html"> Index </a> </li>
<li> <a href="/info.html"> Info </a> </li>
</ul>
<p> Bienvenido/a a la página principal </p>
</body>
</html>
E info.html:
<!DOCTYPE>
<html>
<head>
<title> Ejemplo de Node.js </title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<h1> Info </h1>
<ul>
<li> <a href="/index.html"> Index </a> </li>
<li> <a href="/info.html"> Info </a> </li>
</ul>
<p> Esta es la página info </p>
</body>
</html>
Hasta acá todo muy lindo, pero tenemos un problema, y es que nuestra aplicación sólo es capaz de devolver al cliente archivos .html, y nosotros necesitamos devolverle al navegador otro tipo de archivos; js, css e imágenes. Así que una vez más vamos a editar nuestro archivo principal index.js con el siguiente código:
var http = require('http');
var url = require('url');
var fs = require('fs');
var mime_types = {
'js' : 'text/javascript',
'html' : 'text/html',
'css' : 'text/css',
'jpg' : 'image/jpg',
'gif' : 'image/gif',
'png' : 'image/png'
};
http.createServer(function(peticion, respuesta){
var path_nombre = (url.parse(peticion.url).pathname == '/') ? '/index.html' : url.parse(peticion.url).pathname;
var ruta_a_archivo = 'contenido/' + path_nombre;
fs.exists(ruta_a_archivo, function(existe){
if(existe){
fs.readFile(ruta_a_archivo, function(error, contenido_archivo){
if(error){
respuesta.writeHead(500, 'text/plain');
respuesta.end('Error interno.');
}else{
var extension = ruta_a_archivo.split('.').pop();
var mime_type = mime_types[extension];
respuesta.writeHead(200, {'Content-Type': mime_type});
respuesta.end(contenido_archivo);
}
});
}else{
respuesta.writeHead(404, 'text/plain');
respuesta.end('Error 404. El enlace no existe o ha dejado de existir.');
}
});
}).listen(3000, '127.0.0.1');
console.log('El servidor esta funcionando correctamente en https://localhost:3000/');
Como se ve, aquí creamos un json con la lista de mimetype que será capaz de devolver nuestro servidor:
var mime_types = {
'js' : 'text/javascript',
'html' : 'text/html',
'css' : 'text/css',
'jpg' : 'image/jpg',
'gif' : 'image/gif',
'png' : 'image/png'
};
Antes de devolver una respuesta buscamos el tipo de archivo mediante su extensión (.html, .css. js, etc):
var extension = ruta_a_archivo.split('.').pop();
Y luego buscamos el mimetype que le corresponde a la extensión:
var mime_type = mime_types[extension];
Se lo pasamos a la cabecera y devolvemos el contenido del archivo al cliente:
respuesta.writeHead(200, {'Content-Type': mime_type});
respuesta.end(contenido_archivo);
Para probar esto podemos editar nuestra hoja de estilos dentro de contenido/css/style.css agregando, por ejemplo un color de fondo:
body {
background-color: #D4ECF8;
}
Y dentro de contenido/index.html vamos a importar esta la hoja de estilos:
<!DOCTYPE>
<html>
<head>
<title> Ejemplo de Node.js </title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link type="text/css" href="/css/style.css" rel="stylesheet" />
</head>
<body>
<h1> Index </h1>
<ul>
<li> <a href="/index.html"> Index </a> </li>
<li> <a href="/info.html"> Info </a> </li>
</ul>
<p> Bienvenido/a a la página principal </p>
</body>
</html>
Y ahora ya podemos probar nuestra aplicación, como en la publicación anterior. Abrimos la consola y con el comando cd entramos en la ubicación de nuestro proyecto, en mi caso:
cd C:\Program Files\nodejs\estatica
Y compilamos el archivo index.js:
node index.js
Bien, de esta forma tenemos nuestra primer aplicación node.js con archivos estáticos.
Anterior: Introducción a Node.js, parte 1: Instalación… Hola mundo
Siguiente: Introducción a Node.js, parte 3: Crear módulos

No se logra vincular el archivo CSS.
Yamil, incluiste la parte del código de los minetypes, para detectar el tipo de archivo al que se está intentando acceder?
Te dejo un ejemplo en el repositorio del github que funciona:
https://github.com/fernandoggaitan/nodejs_ejemplo_pagina_estatica
Saludos!
Hola Ferchu, un gusto de conocerte por este medio. Tuve la fortuna de leer tu trabajo sobre node.js el cual a sido de mucha ayuda.
Ahora me ocurrió una inquietud que no logro responderme.
Al realizar el ejercicio de Pagina Estatica cambié la ip 127.0.0.1 por la que tiene el pc donde esta el servidor.
El problema es que no logro ver la pagina estática desde todos los equipos de mi oficina. solo lo logro de la mía y de otra sercana a mi escritorio, pero cuando voy por el resto de las oficinas no logro cargar la pagina. ¿Podés hacerme algún comentario que me oriente a resolver el problema?. Muchas Gracias
Hola, Humberto, cómo te va.
Esa IP se accede a través de algunas de las máquinas. Entonces lo más probable es que las otras máquinas no tengan acceso a ese servidor. Por casualidad tendrás otro servicio ahí que sí pueda accederse desde las otras máquinas, por ejemplo algún proyecto PHP o Java?
Lo único que se me viene a la cabeza es que esas máquinas que no tengan acceso, y en ese caso deberías hablar con el encargado de redes de tu trabajo.
Saludos!
B. Días (muy gentil de tu parte en responderme).
Mirá yo me encuentro en una Oficina Pública. Cuenta con 5 Pc Desktop conectadas por cable UTP y la mía vía Wifi.
Probaré de llamar al Área de sistemas para consultar. Te gradezco el comentario.
empiezo hoy espero aprender todo
todo bien hasta que modifique por ultima vez index.js de la carpeta principal y no me sale info.html, ni / me sale error 404
Compilá nuevamente el archivo index.js, con:
node index.js
Saludos!
fue error mio ya lo corregi habia creado mal la carpeta contenido, ademas me di cuenta que funciona muy bien incluso sin poner el mine types ,
Perfectirijillo, Fredd!
Saludos!
Hola Fernando, espero que no te disgustes, solo quería decir que no es minetype sino mimetype, y preguntarte que opinas si en lugar de dividir la ruta del archivo y tomar la ultima porción después del punto (ruta.split(«.»).pop()) por que no mejor usar el metodo extname que ofrece la API de Nodejs. a proposito me gusto el metodo que usaste para simular este metodo.
Sí, lo teclié mal, gracias por avisar.
Saludos!
No puedo servir los archivos index.html, hise todod tal cual no se si me falto instalar un npm o algo, espero me puedas ayudar
Víctor fijate cómo está hecho acá:
https://github.com/fernandoggaitan/nodejs_ejemplo_pagina_estatica
Saludos!
Exelente tutorial 😀
Muchas gracias Moises.
Hola, tu tutorial está fantástico. Me han dejado hacer una aplicación con node.js, sesiones y MongoDB. Sinceramente soy alguien que ve muchas fuentes y compara información y te felicito rotundamente, tus tutos están muy bien explicados, paso a paso, recibe una muy fuerte felicitación, me haré todos los tutos para aprender mucho de Node.js.
Gracias, que tengas un buen día.