Sirviendo archivos estáticos con Node.js

Un problema típico que afrontaras en Node.js, es que NO suministra archivos estáticos en las peticiones de paginas HTML en forma implícita, presentando problemas como NO mostrar el favicon, NO cagar correctamente el .CSS o los archivos JavaScript relacionados a BootStrap.

Este es lamentablemente un problema de entendimiento, que trataremos de aclararte a continuación, habitualmente cuando se carga una pagina HTML, esta va acompañado de una petición http “GET” en servidores de tipo IIS o Apache estos reciben una URL igual a “./” o simplemente “/” indicando que desean visualizar el raiz de nuestro sitio web o dominio (www.mi_sitio.com), este resuelve cargando la pagina por defecto, posiblemente una /index.html, /index.asp o /default.html, si nuestra pagina va acompañada de recursos externos como un archivo .CSS o .js este intentara hacer una nueva petición al servidor solicitando estos archivos, si estos están disponibles en la carpeta del servidor y en la ruta indicada, los proporcionara sin mayor problema. En el caso de Node.js, debes de indicarlo en forma explicita, suministrando este recurso.

Que quiere decir esto, que una pagina típica como la siguiente:

<!DOCTYPE html>
<html>
   <head>
      <title/>Pagina HTML tipica</title>
      <link rel="icon" href="favicon.ico" type="image/x-icon"/>
      <link type="text/css" rel="stylesheet" href="style.css" />
      <script type="text/javascript" src="jquery-1_6.js"></script>
   </head>
   <body>
   <p>Esta pagina incluye icono, css, javascript</p>
   </body>
   <script type="text/javascript">
      $(document).ready(function() 
      { 
         alert('Una Alerta'); 
      });
   </script>
</html>

Presentara al menos los siguientes problemas:

  • Node.js NO muestra el icono de pagina favicon
  • Node.js NO cagar correctamente el .CSS (Hoja de estilos)
  • Node.js NO ejecuta los archivos JavaScript relacionados a BootStrap

En toda petición desde un navegador, sin importar que este incluya o no Hojas de estilo (.CSS) o código JavaScript (.js), siempre realizara dos peticiones, uno para cargar la pagina inicial (./index.html), y la otra para solicitar el icono asociado a la pagina favicon.ico (que es el icono asociado de nuestro sitio web), sin importar que este incluya explicita mente la referencia a este (linea 5 del ejemplo de pagina HTML típica).

Como todo recurso solicitado en una petición Web, este debe ser suministrado por nuestro servidor, eso no excluye a los recursos como archivos de Hojas de Estilo (.css) y JavaScript (.js), existe para nuestro caso dos posibles soluciones:

  • Hacer referencia a nuestros archivos de recursos a través de un link-href / src indicando la url donde se encuentra nuestro recurso, afuera de nuestro servidor de aplicación (un alojamiento de archivos de un tercero).
  • Hacer que nuestro servidor Node.js suministre los archivos Requeridos, definiendo en nuestro Servidor Http de peticiones las responda en forma explicita.

 

Node.js No muestra el icono de página favicon


El problema de NO mostrar el favicon, se manifiesta, cuando al carga una pagina como el ejemplo anterior, a pesar que esta la referencia a la ruta y recurso requerido del icono, este no es suministrado por nuestro servidor Node.js en forma implícita.

Esto se resuelve de la siguiente manera:

var http = require('http');
var fs = require('fs');

http.createServer(function (request, response) 
{
   console.log('Recibiendo peticiones...');

   if (request.url === '/favicon.ico')
   {
      console.log("El manejador de solicitudes 'favicon' fue invocado.");

      var img = fs.readFileSync('./favicon.ico');
      response.writeHead(200, {"Content-Type": "image/x-icon"});
      response.end(img,'binary');
   }

   if (request.url === '/')
   {
      ...
      Mostrando mi sitio web
      ...
   }
}).listen(8125);

 

Como habrás notado ya, en la linea 8, se evalúa si se esta solicitando nuestro icono de sitio web (favicon), posteriormente se utiliza el modulo de Node.js FileSystem (fs, linea 2), el cual nos da acceso a los archivos del sistema en el servidor, desde donde leemos y respondemos a la petición proporcionando el contenido del archivo de nuestro icono utilizando readFileSync (linea 12 a 14). Favor poner atención al tipo de contenido que es devuelto en la respuesta a la petición “Content-Type”: “image/x-icon“, y el formato del archivo Binary.

Otra forma de resolverlo, como habíamos mencionado anteriormente, es adicionando el Link de referencia a un servidor que tenga alojado nuestros archivos de imágenes.

<link rel="icon" href="http://www.SERVIDOR_EXTERNO.com/RUTA/favicon.ico" type="image/x-icon"/>

Como notaras esta es la solución menos preferible, ya que nuestros recursos están fuera de nuestro servidor, y son administrados por un tercero, en todo caso, sigue siendo una alternativa valida.

 

Node.js NO carga correctamente el .CSS (Hoja de estilos)


Posiblemente a estas alturas ya dedujiste cual es el problema, y consecutivamente su solución, pero igual vamos a remarcar el problema de que Node.js NO carga correctamente el .CSS (Hoja de estilos), por cada linea en el <head></head> que haga referencia a un archivo de hojas de estilo (.css), se realizara una petición solicitando este recurso. Necesitamos responder en forma explicita y suministrarlo, de la siguiente manera:

var http = require('http'); 
var fs = require('fs'); 

http.createServer(function (request, response) 
{ 
   console.log('Recibiendo peticiones...');
   
   if (request.url === '/css/style.css')
   { 
      console.log("El manejador de solicitudes 'css' fue invocado."); 
     
      var cssfile = fs.readFileSync('./css/style.css'); 
      response.writeHead(200, {"Content-Type": "text/css"}); 
      response.end(cssfile,'utf-8'); 
   }

   if (request.url === '/') 
   {
      ... 
      Mostrando mi sitio web 
      ... 
   }
}).listen(8125); 

 

Como habrás notado ya, en la linea 8, se evalúa si se esta solicitando nuestro archivo de hojas de estilo (style.css), posteriormente se utiliza el modulo de Node.js FileSystem (fs, linea 2), de igual forma que el ejemplo de favicon, en este nuevo caso, el tipo de archivo que devolvemos es “text/css” a diferencia que el favicon que fue “image/x-icon” (linea 13 en ambos ejemplos), también el formato de el archivo es devuelto en formato ‘utf-8‘ en lugar de un Binary. Por lo demás el proceso es el mismo.

Existe una alternativa diferente de solventar el problema, como en el caso de los favicon, es adicionando el Link de referencia a un servidor que tenga alojado nuestros archivos de hojas de estilos (.css).

<head>
   <link rel="stylesheet" type="text/css" href="http://www.SERVIDOR_EXTERNO.com/RUTA/mystyle.css" />
</head>

Como notaras esta es la solución menos preferible, como habíamos ya mencionado en reiteradas ocasiones, ya que nuestros recursos están fuera de nuestro servidor, y son administrados por un tercero, en todo caso, sigue siendo una alternativa valida.

 

Node.js NO ejecuta los archivos JavaScript relacionados a BootStrap


Para incluir los recursos de archivos JavaScript (.js), como por ejemplo los archivos requeridos para BootStrap, es común incluirlos en nuestro sitio web, con el objetivo de evitar los problemas que surgen cuando existen cambios de versión. ¡Si!, como ya habrás notado, el problema sigue siendo similar a los dos casos anteriores, excepto por unos pequeños cambios.

Vayamos inmediatamente al ejemplo con la solución, incluyendo los cambios:

var http = require('http'); 
var fs = require('fs'); 

http.createServer(function (request, response) 
{ 
   console.log('Recibiendo peticiones...'); 

   if (request.url === '/js/jquery.min.js')
   {
      console.log("El manejador de solicitudes 'js' fue invocado."); 

      var jsfile = fs.readFileSync('./js/jquery.min.js'); 
      response.writeHead(200, {"Content-Type": "text/javascript"}); 
      response.end(jsfile,'utf-8'); 
   } 

   if (request.url === '/') 
   { 
      ... 
      Mostrando mi sitio web 
      ... 
   } 
}).listen(8125);

Favor prestar especial atención a la linea 13, donde el tipo de contenido es ‘text/javascript‘, que es la principal diferencia en el tipo de contenido, y la linea 14 con el tipo de archivo ‘utf-8‘.

 

Resumen


Como todo recurso solicitado en una petición Web, este debe ser suministrado por nuestro servidor, eso no excluye a los recursos como archivos de Hojas de Estilo (.css) y JavaScript (.js), existe para nuestro caso dos posibles soluciones:

  • Hacer referencia a nuestros archivos de recursos a través de un link-href / src indicando la url donde se encuentra nuestro recurso, afuera de nuestro servidor de aplicación (un alojamiento de archivos de un tercero).
  • Hacer que nuestro servidor Node.js suministre los archivos Requeridos, definiendo en nuestro Servidor Http de peticiones las responda en forma explicita.

 

Hacer referencia a nuestros recursos mediante un tercero

Solventar .ico Favicon

<link rel="icon" href="http://www.SERVIDOR_EXTERNO.com/RUTA/favicon.ico" type="image/x-icon" />

Solventar .css

<!-- Ultima versión minimizada de .CSS de BootStrap alojado en su servidor oficial -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />

Solventar .js de BootStrap

<!-- Ultima versión minimizada de biblioteca jquery.min.js en Servidor Google CDN -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<!-- Ultima versión minimizada de biblioteca jquery.min.js en Servidor Microsoft CDN -->
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>

<!-- Ultimo compilado JavaScript BootStrap alojado en el servidor oficial -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

 

Hacer que Node.js Sirva archivos estáticos

Valernos del modulo de Node.js FileSystem (fs), para acceder a los archivos

var fs = require('fs'); 

Identificar la peticion mediante la url

if (request.url === '/favicon.ico')
if (request.url === '/css/style.css')
if (request.url === '/js/jquery.min.js')

Acceder al recurso en el servidor, del archivo respectivo

var file = fs.readFileSync('./Ruta/NombreArchivo.Ext'); 

Definir el Tipo de Contenido en la respuesta, dependiendo del tipo de archivo

response.writeHead(200, {"Content-Type": CONTENT-TYPE});

//Donde CONTENT-TYPE pueden ser 
"Content-Type": "image/x-icon"      // Archivo favicon .ico
"Content-Type": "text/css"          // Archivo Hoja de Estilos .css
"Content-Type": "text/javascript"   //Archivos JavaScript .js

Escribir el contenido del archivo en la respuesta, el formato adecuado

 
response.end(img, 'binary');    // Archivo favicon .ico 
response.end(cssfile, 'utf-8'); // Archivo Hoja de Estilos .css 
response.end(jsfile, 'utf-8');  // Archivos JavaScript .js 

 

Es muy probable que NO se ha visualizado en forma obvia, que Node.js no suministra los archivos habituales en el desarrollo de una aplicación WEB, pero…

Necesitas definir todos y cada uno de los archivos necesarios, para el correcto funcionamiento de tu página web. Esto incluye .ico, .css, .js, .mp3, .acc (audio) , .mp4, .avi, .mpeg (vídeo), .ttf, .woff, woff2, (fuentes de letras), .jpg, .jpeg, .gif (imagenes), .csv, .json,  etc. etc. etc…

Esto implica incluir el código necesario para poder suministrar todos y cada uno de los tipos de archivos que requieras, para una lista completa del Content-Type visita este Link, ante cualquier duda sobre el formato prueba utilizar ‘utf-8‘.

Soluciones Alternativas

Existen maneras alternativas de resolver este problema, aunque como ya has visto, el problema es fácil de resolver una vez se comprende en que consiste y la forma de solventarlo.
Pero siendo prácticos, en un proyecto REAL, de grandes dimensiones, el numero de archivos .css y de script .js es increíblemente grande y ponerlos disponibles en un servidor externo de un tercero, es una solución poco convencional, sin mencionar las vulnerabilidades de seguridad que surgirían.
Otra situación es la cantidad de código que hay que incorporar para poner a disposición todos nuestros archivos .css y .js.
Teniendo presente todo esto ultimo, seria útil crear una funcionalidad en nuestro servidor que sirva las peticiones de todos estos archivos (.css, .js) en forma automática, que es algo que hemos abordado en nuestro articulo “Sirviendo archivos estáticos con Node.js – Código Automatizado”, donde mostramos el código automatizado para responder a todas estas peticiones.

Existen también módulos creados para Node.js como es el caso de Express, el cual incluye (entre otras características) una solución que consiste en crear una directorio/carpeta llamada ‘public‘ donde es colocado todo el contenido que deseamos compartir desde nuestro servidor Node.js y este lo suministrara en forma automática, siempre y cuando se encuentre dentro de esta carpeta. Soluciones similares son ofrecidas por Módulos como:

 


links & referencias: 

si deseas mas información o consultar las fuentes bibliográficas, aquí te dejamos…

 

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *