2.4 · Crear un servidor HTTP nativo

Nivel 2 · Núcleo de Node.js

2.4Crear un servidor HTTP nativo

Objetivo: Crear un servidor HTTP con el módulo nativo (req/res, enrutamiento manual, códigos y cabeceras HTTP) y comprender la base sobre la que está construido Express.
Tiempo estimado: 11 min · lectura autónoma · Si solo tienes 5 min: lee «Lo esencial en 30s» + el esquema.

Lo esencial en 30 segundos

  • Un servidor en pocas líneas: createServer((req, res) => ...) luego .listen(puerto) — cada petición dispara la función.
  • req lee, res responde: método, url y cabeceras por un lado; estado, cabeceras y cuerpo por otro — el vocabulario HTTP de las API.
  • A mano, luego Express: enrutar con if y analizar el cuerpo muestra lo que Express simplifica — nunca caja negra.

Minicaso hilado — Salim sirve el inventario en el navegador

Último acto: Salim quiere que el equipo consulte el inventario (2.1) desde el navegador, sin instalar nada. Crea un servidor con el módulo http: una ruta que lista los informes en JSON, una que muestra la bienvenida en HTML, un 404 para el resto — todo enrutado a mano según req.method y req.url. Sufriendo con el análisis del cuerpo y la cascada de if, comprende exactamente lo que Express (nivel 3) le simplificará. El proyecto del nivel 2 está entregado: archivos, eventos, streams, servidor.

Epílogo del hilo 2.1-2.3: la herramienta de Salim se convierte en un servidor consultable por el equipo.

1. Un servidor web sin dependencia

Node crea servidores web y API con su módulo nativo http, sin ninguna dependencia — y hacerlo «a mano» ANTES de Express es muy formativo. Se crea un servidor con http.createServer() pasándole una función llamada con CADA petición: recibe req (request: método GET/POST, URL, cabeceras, cuerpo) y res (response: lo que se construye y devuelve). Luego .listen(puerto) escucha las conexiones (ej. 3000). Pocas líneas para un servidor funcional: Salim muestra el inventario en el navegador del equipo con una decena de líneas.

2. req, res y el vocabulario HTTP

Del lado de la petición, req aporta req.method (GET, POST, PUT, DELETE…), req.url (la ruta, ej. /rapports), req.headers — y para un POST, el cuerpo se lee como un stream (sección 2-3), trozo a trozo. Del lado de la respuesta, res construye: res.statusCode = 200, res.setHeader('Content-Type', 'application/json'), res.write(...) luego res.end(...). Hay que conocer HTTP: los métodos (GET leer, POST crear, PUT/PATCH modificar, DELETE eliminar — el vocabulario de las API REST, sección 4-1), los códigos (200 OK, 201 Created, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error…), las cabeceras (tipo de contenido, autenticación, caché…).

3. Todo a mano — luego Express

En nativo, se gestiona TODO a mano: enrutar según URL y método (cascada de if), analizar el cuerpo, definir las cabeceras, gestionar los errores — rápido tedioso para una verdadera aplicación. Ahí es donde interviene Express (sección 3-1): enrutamiento elegante, análisis del cuerpo, middlewares — pero todo se basa EN el módulo http. Crear un servidor nativo es pues un ejercicio fundacional: revela la base (req/res, HTTP, puertos) y hace apreciar lo que aporta un framework. No se escribirán servidores nativos en producción (se usará Express), pero esta comprensión marca la diferencia entre usar Express comprendiéndolo y sufrirlo en caja negra — incluso para depurar cuando la «magia» falla.

Error frecuente de interpretación: «Como voy a usar Express, puedo saltar el servidor nativo». No. Sin lo nativo, Express es magia: app.get() «funciona» sin que se sepa que llega una petición, que hay que enrutar según método y URL, definir estado y cabeceras, enviar un cuerpo. Habiendo enrutado a mano y analizado un cuerpo en stream, se MIDE lo que Express simplifica — y cuando falta una cabecera o un cuerpo no está analizado, se sabe diagnosticar en lugar de quedar indefenso. Pocas líneas de nativo evitan meses de caja negra: Salim enrutó tres rutas a mano antes de tocar Express.
El ciclo de una petición Del cliente a la respuesta Cliente Navegador:GET /rapportsServidor createServer: funciónllamada con cada peticiónEnrutamiento if sobrereq.method + req.urlRespuesta res: estado,cabeceras, cuerpo, end()
Del cliente a la respuesta
Versión en texto del esquema (SEO / lectores de pantalla / traducción): 1) El CLIENTE envía una petición: método + ruta + cabeceras (ej. GET /rapports). 2) El SERVIDOR de Salim la recibe: http llama a su función con (req, res) — el servidor es un EventEmitter que emite con cada petición. 3) ENRUTA a mano: unos if sobre req.method y req.url eligen la respuesta (lista JSON, bienvenida HTML, 404). 4) RESPONDE con res: statusCode, Content-Type, cuerpo vía end(). Lección: este ciclo manual es la base — Express lo automatiza sin reemplazarlo.

¿Lo sabía?

Salim mostró su servidor «diez líneas» al equipo — y su responsable creyó que había instalado un framework.
Verdadero: el módulo http nativo basta para servir una página y una API, sin instalar nada.

Diez líneas de nativo valen más que un framework sufrido.

🔎 Ejemplo concreto — 🔎 Ejemplo concreto — El servidor de inventario de Salim

Tres rutas enrutadas a mano, como en casa de Salim:

GET /          → 200, page d'accueil HTML
GET /rapports  → 200, inventaire en JSON (Content-Type: application/json)
Autre chemin   → 404, message d'erreur
POST /rapports → 201 après lecture du corps en stream

Lectura: cada combinación método + URL tiene su respuesta y su estado.

Lección: se mide lo que Express simplificará (enrutamiento, análisis).

Vocabulario de la sección

http (módulo nativo)
Módulo que crea un servidor web sin dependencia: http.createServer() con una función llamada con cada petición, luego .listen(puerto).

Ejemplo sencillo: Salim sirve el inventario en el puerto 3000 con diez líneas.

Lo que no es: un framework como Express (que se basa en él).

Reflejo: comprender la base antes de usar el framework.

req (request)
Objeto de la petición entrante: método (req.method), ruta (req.url), cabeceras (req.headers), cuerpo leído como un stream para POST.

Ejemplo sencillo: Salim enruta según req.method y req.url.

Lo que no es: el objeto con el que se construye la respuesta (es res).

Reflejo: leer la demanda = req.

res (response)
Objeto de construcción de la respuesta: estado (res.statusCode), cabeceras (res.setHeader), cuerpo (res.write/res.end).

Ejemplo sencillo: Salim devuelve res.statusCode = 200 luego res.end(JSON.stringify(...)).

Lo que no es: la petición enviada por el cliente (es req).

Reflejo: construir la respuesta = res, y terminar siempre con end().

Métodos y códigos HTTP
Métodos: GET (leer), POST (crear), PUT/PATCH (modificar), DELETE (eliminar). Códigos: 200 OK, 201 Created, 400/401/404 (cliente), 500 (servidor).

Ejemplo sencillo: GET /rapports → 200, POST /rapports → 201, ruta desconocida → 404.

Lo que no es: un 200 devuelto para todo, éxitos como errores.

Reflejo: cada respuesta = el verbo correcto + el código correcto.

Lo que Express simplifica
Lo nativo lo gestiona todo a mano (enrutamiento con if, análisis del cuerpo, cabeceras); Express aporta enrutamiento, análisis, middlewares — sobre el módulo http.

Ejemplo sencillo: Salim reemplaza su cascada de if por app.get('/rapports', ...) en el nivel 3.

Lo que no es: un servidor competidor que reemplaza http.

Reflejo: tedioso a mano = necesidad cubierta por Express.

En la práctica — En la práctica — Crear un servidor HTTP nativo

  1. Cree un servidor con http.createServer((req, res) => {...}) y arránquelo con .listen(3000); pruébelo en el navegador (localhost:3000).
  2. Devuelva una respuesta: defina res.statusCode, res.setHeader('Content-Type', ...) y termine con res.end('Hello').
  3. Enrute «a mano» según req.method y req.url (una cascada de if): devuelva respuestas distintas según la ruta.
  4. Devuelva JSON (Content-Type application/json + res.end(JSON.stringify(data))) y compruebe cuánto gestionar todo a mano se vuelve rápido tedioso.
Crea un servidor HTTP con el módulo nativo (req/res, enrutamiento manual, códigos y cabeceras HTTP) y comprende la base sobre la que está construido Express — el «bajo el capó».

Script listo para decir — defender el ejercicio nativo antes de Express (30 s)

«Antes de Express, enruté tres rutas a mano: sé lo que es una petición, cómo se elige la respuesta según el método y la URL, y por qué cada estado cuenta. Ahora, cuando escriba app.get, sabré lo que Express hace por mí — y cuando se rompa, sabré dónde mirar.»

Para decir mostrando el servidor nativo funcionando en localhost:3000; la demo en el navegador convence.

Modelo copiar-pegar — servidor nativo con enrutamiento manual

const http = require('node:http');

const rapports = [
  { nom: 'rapport-01.txt', taille: 1240 },
  { nom: 'rapport-02.txt', taille: 986 }
];

const serveur = http.createServer((req, res) => {
  if (req.method === 'GET' && req.url === '/') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.end('

Inventaire des rapports

'); } else if (req.method === 'GET' && req.url === '/rapports') { res.statusCode = 200; res.setHeader('Content-Type', 'application/json; charset=utf-8'); res.end(JSON.stringify(rapports)); } else { res.statusCode = 404; res.setHeader('Content-Type', 'text/plain; charset=utf-8'); res.end('Non trouvé'); } }); serveur.listen(3000, () => console.log('Serveur sur http://localhost:3000'));

Demo local

localhost:3000 ante el equipo: el inventario de Salim se muestra en el navegador, cero despliegue.

API JSON de equipo

GET /rapports devuelve el inventario en JSON: los colegas lo consumen desde sus propios scripts.

Archivo grande que servir

Enviar la exportación de 2 Go: se conecta un createReadStream hacia res (sección 2.3) en lugar de cargarlo todo.

Hacia Express

En cuanto los if se apilan: app.get('/rapports', ...) reemplaza la cascada — misma base http debajo.

✓ Buenas prácticas

  • Pruebe cada ruta en el navegador o con curl (método + URL + estado).
  • Devuelva siempre el estado correcto (201 tras creación, 404 si desconocido, 500 en caso de error).
  • Termine cada respuesta con res.end(), si no el cliente espera indefinidamente.

✗ Errores frecuentes

  • Saltar lo nativo y sufrir Express en caja negra.
  • Devolver 200 para todo, éxitos como errores.
  • Olvidar res.end() (petición que queda pendiente indefinidamente).

Puntos clave

  • Node crea servidores web con el módulo nativo http (sin dependencia): http.createServer((req, res) => ...) luego .listen(puerto). Formativo ANTES de Express.
  • req = la petición (método, url, headers, cuerpo en stream); res = la respuesta (statusCode, setHeader, write/end).
  • Conocer HTTP: MÉTODOS (GET/POST/PUT/DELETE) y CÓDIGOS DE ESTADO (200, 201, 400, 401, 404, 500) — el vocabulario de las API REST.
  • El servidor nativo lo gestiona TODO a mano (enrutamiento con if, análisis del cuerpo, cabeceras) → rápido tedioso; Express lo simplifica pero SE BASA en http.

Desafío 48h — aplique mañana

Ponga en línea el servidor del modelo con sus datos reales (su inventario 2.1): bienvenida HTML, ruta JSON, 404 cuidada. Muéstrelo a un colega en su navegador, luego anote en una frase lo que Express le simplificará.

Lista de salida de la sección
  • Puedo explicar el ciclo petición → enrutamiento → respuesta.
  • Sé servir HTML y JSON con los estados correctos.
  • Un colega consultó mi servidor nativo en su navegador.
Autoevaluación 1-5: ¿domino req/res y los estados?¿comprendo lo que Express hace por mí?

Preguntas frecuentes

¿Por qué aprender el servidor HTTP nativo si voy a usar Express de todos modos?

Para usar Express comprendiendo en lugar de sufrirlo. Habiendo enrutado a mano (cascada de if), analizado un cuerpo en stream y definido las cabeceras, SABE lo que pasa realmente cuando escribe app.get() — y MIDE lo que Express simplifica (enrutamiento elegante, express.json(), middlewares). Sobre todo, depura: cabecera faltante, estado incorrecto, cuerpo no analizado — sabe mirar al nivel correcto en lugar de quedar indefenso cuando la «magia» falla. Como Salim: tres rutas a mano antes del primer app.get.

¿Cuáles son las bases del protocolo HTTP que debo conocer absolutamente?

El ciclo petición → respuesta, los MÉTODOS (GET leer, POST crear, PUT reemplazar, PATCH modificar parcialmente, DELETE eliminar — una misma URL hace cosas distintas según el método), los CÓDIGOS DE ESTADO (2xx éxito: 200 OK, 201 Created; 4xx error de cliente: 400, 401, 403, 404; 5xx error de servidor: 500 — una buena API devuelve el código correcto, no 200 para todo), y las CABECERAS (Content-Type, autenticación, caché). Este vocabulario estructura las API REST (sección 4-1) y se practica desde el servidor nativo: cada ruta de Salim devuelve método, estado y Content-Type correctos.

Comprueba tu comprensión

Una ruta desconocida llega al servidor nativo de Salim. ¿Qué debe devolver?

Recursos adicionales (opcional, para ir más allá)

Examen del nivel 2Preguntas inéditas y más difíciles para validar tus conocimientos