Menu

Servidor HTTP en Node.js: http.createServer con ejemplos

http.createServer() recibe una función que se ejecuta en cada petición con req y res. Lees el método y la URL de req, y luego pones un status, headers y un body en res y llamas a res.end().

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

http.createServer() crea un servidor web a partir de una función, el request handler, que Node llama en cada petición entrante con dos objetos: req (el método, la URL y los headers que envió el cliente) y res (lo que devuelves). Pon un status code y headers en res, y luego llama a res.end() con el body. server.listen(3000) empieza a aceptar conexiones en el puerto 3000.

La primera petición responde You asked for GET /hello?name=Ada, y la Console registra el mismo método y la misma URL. Envía DELETE /anything desde la barra de petición: responde el mismo handler, porque un servidor http a pelo no tiene rutas. Todas las peticiones pasan por esa única función.

Enviar JSON y definir el status code

res.writeHead(status, headers) define el status code y los headers en una sola llamada. Para JSON, pon Content-Type: application/json y envía el resultado de JSON.stringify(); res.end() solo acepta un string o un Buffer.

GET /users?limit=1 devuelve [{"id":1,"name":"Ada"}]. req.url es la ruta más el query string, así que new URL(req.url, 'http://localhost') lo separa en pathname y searchParams (la base solo está ahí porque URL necesita una dirección absoluta). Envía GET /nothing y el status pasa a 404.

Enrutar peticiones con un switch

Una API pequeña no necesita más que un switch sobre el método y la ruta. Construye una clave como 'GET /users' y dale a cada ruta su propio case:

Envía POST /users con el body {"name": "Grace"}: la respuesta es 201 con {"id":2,"name":"Grace"}, y GET /users ahora lista los dos usuarios. Envía el mismo POST con el body hello y obtienes 400 con {"error":"Body must be JSON"}.

Leer el body de un POST

Node no parsea el body por ti. req es un stream de lectura, y el body llega por trozos mediante eventos data, y después se dispara end cuando está completo. readBody() de arriba junta los trozos en un string y devuelve una promesa, para que el handler pueda hacer await. Como req es iterable de forma asíncrona, este bucle hace el mismo trabajo:

let data = '';
for await (const chunk of req) data += chunk;
const body = JSON.parse(data);

Un servidor real además limita el tamaño (deja de leer y responde 413 cuando data.length pasa de un límite) y comprueba req.headers['content-type'] antes de llamar a JSON.parse.

Errores comunes

Olvidar res.end(). Una rama que define un status pero nunca termina la respuesta deja al cliente esperando hasta que se agota el tiempo.

Definir un header después del body. Cuando ya se ha ejecutado res.end() o el primer res.write(), los headers se han enviado, y res.setHeader() lanza ERR_HTTP_HEADERS_SENT. Usa return cuando envíes una respuesta antes de tiempo, como hacen los ejemplos.

Comparar req.url con una ruta. req.url incluye el query string, así que req.url === '/users' es false para /users?limit=1. Compara pathname.

Cuándo usar Express

El módulo http basta para un health check, un receptor de webhooks o para aprender cómo funciona HTTP. En cuanto necesitas parámetros de ruta como /users/:id, parseo del body JSON, middleware y manejo de errores, acabas escribiendo tu propio framework pequeño. Express es ese framework, construido sobre los mismos objetos req y res; el routing en Express muestra la misma API con app.get() y app.post().

Preguntas frecuentes

¿Qué diferencia hay entre res.write y res.end?

res.write() envía un trozo del body y deja la respuesta abierta, así que puedes llamarlo muchas veces. res.end() envía un último trozo opcional y cierra la respuesta. Cada respuesta necesita exactamente un res.end().

¿Cómo detengo un servidor HTTP de Node?

Llama a server.close(). Deja de aceptar conexiones nuevas en el acto y ejecuta su callback cuando las abiertas han terminado, que es lo que necesita un apagado limpio con SIGTERM.

¿Cómo uso HTTPS con el módulo http?

Usa el módulo https: https.createServer({ key, cert }, handler) recibe el mismo handler más una clave privada y un certificado. En producción, un proxy como Nginx o la plataforma de hosting suele terminar el TLS, y tu servidor de Node sigue escuchando en HTTP plano.

¿En qué puerto debería escuchar un servidor de Node?

Cualquier puerto libre por encima de 1024 funciona sin permisos de administrador; 3000 y 8080 son habituales en desarrollo. Las plataformas de hosting suelen darte el puerto en una variable de entorno, así que escribe server.listen(process.env.PORT || 3000).

Ilustración de los lenguajes de programación de Coddy

Aprende a programar con Coddy

Comenzar