2.4Crear un servidor HTTP nativo
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.
¿Lo sabía?
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
- Cree un servidor con http.createServer((req, res) => {...}) y arránquelo con .listen(3000); pruébelo en el navegador (localhost:3000).
- Devuelva una respuesta: defina res.statusCode, res.setHeader('Content-Type', ...) y termine con res.end('Hello').
- Enrute «a mano» según req.method y req.url (una cascada de if): devuelva respuestas distintas según la ruta.
- Devuelva JSON (Content-Type application/json + res.end(JSON.stringify(data))) y compruebe cuánto gestionar todo a mano se vuelve rápido tedioso.
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á.
- 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.
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.
Una ruta desconocida llega al servidor nativo de Salim. ¿Qué debe devolver?