Lección 12. Primer servidor con Node.js.

Una vez aprendido el funcionamiento base de Node.js, vamos a realizar un nuevo ejercicio; ahora crearemos un pequeño servidor HTTP.

Esto lo haremos con ayuda del módulo nativo de node:http y sus métodos y atributos.

Código base._

Realicemos el primer código, dentro de un archivo, el cual en este ejemplo llamaremos http.js: con el contenido:

Copiar código
// Importa el módulo "http" nativo de Node.js para crear un servidor HTTP.
const http = require("node:http");

// Crea un servidor HTTP que maneja las solicitudes entrantes.
const server = http.createServer((req, res) => {
  // Muestra un mensaje en la consola cuando se recibe una solicitud.
  console.log("request received");

  // Envía una respuesta al cliente con el mensaje "Hola mundo".
  res.end("Hola mundo");
});

// El servidor comienza a escuchar en el puerto 3000.
server.listen(3000, () => {
  // Muestra un mensaje en la consola cuando el servidor está activo.
  console.log("server listening on port 3000");
});

Donde:

const http = require("node:http"); -> permite importar el módulo nativo de node:http.

const server = http.createServer((req, res) => {...}) -> crea un servidor que recibe información cada vez que se hace una petición http.

console.log("request received"); -> Se imprime en el Servidor cuando se detecta una peticion.

res.end("Hola mundo"); -> Respuesta enviada a la petición.

server.listen(3000, () => {...}); -> Contiene el listen para el levantamiento del servidor, el cual, según configuramos, escucha en el puerto 3000.

console.log("server listening on port 3000"); -> Imprime el el servidor el mensaje de escucha.

Nota: Este código esta bien, y funciona, pero tiene algunos detalles, que pasaría si nuestro puerto 3000 se encuentra ocupado, podría haber un error, para que ello nunca suceda, podemos realizar una pequeña modificación a nuestro código en el apartado del puerto.

Código base con automatización de puerto de escucha._

El código seria el siguiente:

Copiar código
// Importa el módulo "http" nativo de Node.js para crear un servidor HTTP.
const http = require("node:http");

// Crea un servidor HTTP que maneja las solicitudes entrantes.
const server = http.createServer((req, res) => {
  // Muestra un mensaje en la consola cuando se recibe una solicitud.
  console.log("Request received");

  // Envía una respuesta al cliente con el mensaje "Hola mundo".
  res.end("Hola mundo");
});

// El servidor comienza a escuchar en un puerto automático.
server.listen(0, () => {
  // Muestra un mensaje en la consola cuando el servidor está activo.
  console.log(`Server listening on http://localhost:${server.address().port}`);
});

Nota: Colocar el puerto 0 NO SIGNIFICA que nuestro servidor correrá en ese puerto, sino que es una forma de colocar, que será el primer puerto libre que encuentre.

server.address().port es un parámetro que permite recuperar el numero de puerto desde el cual nuestro servidor corre.

Nota: IMPORTATE, esto no se recomienda para producción, debido a que en este, el puerto debe ser estático. pero es un buen dato a saber y útil en desarrollo.

Módulo para detección de errores de puertos y asignación._

Crearemos una función, que permite, dado un parámetro (un puerto preferido), si este se encuentra ocupado, ir iterando en 1 hasta encontrar uno vacío.

Lo realizaremos en formato de módulo para exportase y utilizarse en otro archivo.

Copiar código
// Importa el módulo "net" de Node.js, que permite trabajar con servidores y sockets de red.
const net = require("node:net");

// Función para encontrar un puerto disponible a partir de un puerto deseado.
function findAvailablePort(desiredPort) {
  return new Promise((resolve, reject) => {
    // Crea un servidor TCP sin definir comportamiento específico.
    const server = net.createServer();

    // Intenta escuchar en el puerto deseado.
    server.listen(desiredPort, () => {
      // Obtiene el puerto en el que el servidor se inició correctamente.
      const { port } = server.address();

      // Cierra el servidor y resuelve la promesa con el puerto disponible.
      server.close(() => {
        resolve(port);
      });
    });

    // Maneja errores en caso de que el puerto ya esté en uso u otro problema ocurra.
    server.on("error", (err) => {
      if (err.code === "EADDRINUSE") { // Error: el puerto está en uso.
        // Intenta con el siguiente puerto disponible de forma recursiva.
        findAvailablePort(desiredPort + 1).then(port => resolve(port));
      } else {
        // Si el error no es por puerto en uso, rechaza la promesa.
        reject(err);
      }
    });
  });
}

// Exporta la función para que pueda ser utilizada en otros archivos.
module.exports = { findAvailablePort };;
});

Y en el archivo http.js:

Copiar código
// Importa el módulo "http" de Node.js para crear un servidor HTTP.
const http = require("node:http");

// Importa la función "findAvailablePort" desde el archivo "free-port.js".
// Esta función busca un puerto disponible a partir del puerto especificado.
const { findAvailablePort } = require("./free-port");

// Crea un servidor HTTP que maneja solicitudes entrantes.
const server = http.createServer((req, res) => {
  // Muestra un mensaje en la consola cuando se recibe una solicitud.
  console.log("Request received");

  // Envía una respuesta al cliente con el mensaje "Hola mundo".
  res.end("Hola mundo");
});

// Busca un puerto disponible a partir del 3000.
findAvailablePort(3000).then(port => {
  // Una vez encontrado un puerto libre, el servidor comienza a escucharlo.
  server.listen(port, () => {
    // Muestra en consola el puerto en el que está ejecutándose el servidor.
    console.log(`Server listening on http://localhost:${port}`);
  });
});

Si deseamos utilizar una variable de entorno (útil para aplicar en desarrollo y fijar en producción), podemos modificar el http.js un poco, agregando una sola linea de código:

Copiar código
// Importa el módulo "http" de Node.js para crear un servidor HTTP.
const http = require("node:http");

// Importa la función "findAvailablePort" desde el archivo "free-port.js".
// Esta función encuentra un puerto disponible a partir de un puerto dado.
const { findAvailablePort } = require("./free-port");

// Define el puerto deseado, priorizando la variable de entorno PORT si está definida.
// Si PORT no está definida, usa el puerto 3000 por defecto.
const desiredPort = process.env.PORT ?? 3000;

// Crea un servidor HTTP que maneja solicitudes entrantes.
const server = http.createServer((req, res) => {
  // Muestra un mensaje en la consola cuando se recibe una solicitud.
  console.log("request received");

  // Envía una respuesta al cliente con el mensaje "Hola mundo".
  res.end("Hola mundo");
});

// Busca un puerto disponible, comenzando con "desiredPort".
findAvailablePort(desiredPort).then(port => {
  // Una vez encontrado un puerto libre, el servidor comienza a escucharlo.
  server.listen(port, () => {
    // Muestra en consola la URL donde está corriendo el servidor.
    console.log(`Server listening on http://localhost:${port}`);
  });
});

Donde desiredPort es tomado de una variable de entorno process.env.PORT llamada PORT.

Para que esto funcione en desarrollo, levantamos nuestro servidor:

En linux/MAC:

Copiar código
PORT=<puerto-desarrollo> node http.js

En Windows (CMD):

Copiar código
set PORT=<puerto-desarrollo> && node http.js

En Windows (PowerShell):

Copiar código
$env:PORT=<puerto-desarrollo>; node http.js

Configuración y uso de variables archivo de variables de entono en proyecto._

Si no queremos definir manualmente variables cada vez que ejecutemos un servidor, podemos utilizar un archivo:

.env

con la librería dotenv.

Para ello debemos seguir los siguientes pasos:

Paso 1. Instalar la dependencia de dotenv._

Copiar código
npm install dotenv

Nota: Pregunta, ¿Esta es una dependencia de desarrollo o de producción?

Paso 2. Crea un archivo `.env` en la raíz del proyecto._

Copiar código
PORT=4000

Paso 3. Carga las variables en tu código Node.js._

Copiar código
require("dotenv").config(); // Cargar variables desde .env

const port = process.env.PORT ?? 3000;
console.log(`Server listening on http://localhost:${port}`);

Nota: Al ejecutar node server.js, PORT tomará el valor de .env.