TechLead
Lección 4 de 6
7 min de lectura
Node.js

Servidor HTTP de Node.js

Crear servidores web con el módulo http integrado

# Servidor HTTP de Node.js El módulo `http` integrado de Node.js te permite crear servidores web y manejar solicitudes HTTP sin dependencias externas. Es la base de frameworks como Express. ## Servidor HTTP Básico ### Servidor Simple ```javascript const http = require('http'); // Crear servidor const server = http.createServer((req, res) => { // Establecer encabezado de respuesta res.writeHead(200, { 'Content-Type': 'text/plain' }); // Enviar respuesta res.end('¡Hola, Mundo!'); }); // Escuchar en puerto const PORT = 3000; server.listen(PORT, () => { console.log(`Servidor ejecutándose en http://localhost:${PORT}`); }); ``` ### Objeto Request El objeto `req` contiene información sobre la solicitud HTTP: ```javascript const server = http.createServer((req, res) => { // Información de la solicitud console.log('Método:', req.method); // GET, POST, etc. console.log('URL:', req.url); // /ruta?query=valor console.log('Encabezados:', req.headers); // Objeto de encabezados res.end('Solicitud recibida'); }); ``` ### Objeto Response El objeto `res` se usa para enviar respuestas de vuelta: ```javascript const server = http.createServer((req, res) => { // Establecer código de estado y encabezados res.writeHead(200, { 'Content-Type': 'text/html', 'X-Custom-Header': 'valor' }); // O establecer encabezados individualmente res.setHeader('Content-Type', 'text/html'); res.statusCode = 200; // Enviar respuesta res.write('

Hola

'); res.end('

Mundo

'); }); ``` ## Enrutamiento Manejar diferentes rutas y métodos HTTP: ```javascript const http = require('http'); const url = require('url'); const server = http.createServer((req, res) => { const parsedUrl = url.parse(req.url, true); const path = parsedUrl.pathname; const method = req.method; // Ruta home if (path === '/' && method === 'GET') { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end('

Página de Inicio

'); } // Ruta about else if (path === '/about' && method === 'GET') { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end('

Acerca de Nosotros

'); } // Ruta API else if (path === '/api/users' && method === 'GET') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify([ { id: 1, nombre: 'Juan' }, { id: 2, nombre: 'María' } ])); } // Ruta no encontrada else { res.writeHead(404, { 'Content-Type': 'text/html' }); res.end('

404 - Página No Encontrada

'); } }); server.listen(3000); ``` ## Manejo de Solicitudes POST Leer datos del cuerpo de la solicitud: ```javascript const http = require('http'); const server = http.createServer((req, res) => { if (req.method === 'POST' && req.url === '/api/users') { let body = ''; // Recopilar datos req.on('data', chunk => { body += chunk.toString(); }); // Procesar cuando se complete req.on('end', () => { try { const data = JSON.parse(body); console.log('Datos recibidos:', data); res.writeHead(201, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ mensaje: 'Usuario creado', usuario: data })); } catch (err) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'JSON inválido' })); } }); } else { res.writeHead(404); res.end(); } }); server.listen(3000); ``` ## Parámetros de Query Analizar parámetros de query string: ```javascript const http = require('http'); const url = require('url'); const server = http.createServer((req, res) => { const parsedUrl = url.parse(req.url, true); const query = parsedUrl.query; if (parsedUrl.pathname === '/search') { // http://localhost:3000/search?q=node&category=backend console.log('Término de búsqueda:', query.q); console.log('Categoría:', query.category); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ busqueda: query.q, categoria: query.category })); } else { res.writeHead(404); res.end(); } }); server.listen(3000); ``` ## Servir Archivos HTML Servir archivos estáticos: ```javascript const http = require('http'); const fs = require('fs'); const path = require('path'); const server = http.createServer((req, res) => { // Construir ruta de archivo let filePath = path.join( __dirname, 'public', req.url === '/' ? 'index.html' : req.url ); // Obtener extensión de archivo const extname = path.extname(filePath); // Tipos de contenido const contentTypes = { '.html': 'text/html', '.css': 'text/css', '.js': 'text/javascript', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpg', '.gif': 'image/gif' }; const contentType = contentTypes[extname] || 'text/plain'; // Leer y servir archivo fs.readFile(filePath, (err, content) => { if (err) { if (err.code === 'ENOENT') { // Archivo no encontrado res.writeHead(404, { 'Content-Type': 'text/html' }); res.end('

404 - Archivo No Encontrado

'); } else { // Error del servidor res.writeHead(500); res.end(`Error del servidor: ${err.code}`); } } else { // Éxito res.writeHead(200, { 'Content-Type': contentType }); res.end(content); } }); }); server.listen(3000); ``` ## Ejemplo: API REST Completa Un servidor API completo con CRUD: ```javascript const http = require('http'); const url = require('url'); // Almacén de datos en memoria let users = [ { id: 1, nombre: 'Juan', email: 'juan@ejemplo.com' }, { id: 2, nombre: 'María', email: 'maria@ejemplo.com' } ]; let nextId = 3; const server = http.createServer((req, res) => { const parsedUrl = url.parse(req.url, true); const path = parsedUrl.pathname; const method = req.method; // Habilitar CORS res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // Manejar solicitudes preflight if (method === 'OPTIONS') { res.writeHead(204); res.end(); return; } // GET /api/users - Obtener todos los usuarios if (path === '/api/users' && method === 'GET') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(users)); } // GET /api/users/:id - Obtener usuario por ID else if (path.match(/^/api/users/d+$/) && method === 'GET') { const id = parseInt(path.split('/')[3]); const user = users.find(u => u.id === id); if (user) { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(user)); } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Usuario no encontrado' })); } } // POST /api/users - Crear nuevo usuario else if (path === '/api/users' && method === 'POST') { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', () => { try { const newUser = JSON.parse(body); newUser.id = nextId++; users.push(newUser); res.writeHead(201, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(newUser)); } catch (err) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'JSON inválido' })); } }); } // PUT /api/users/:id - Actualizar usuario else if (path.match(/^/api/users/d+$/) && method === 'PUT') { const id = parseInt(path.split('/')[3]); let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', () => { try { const updates = JSON.parse(body); const index = users.findIndex(u => u.id === id); if (index !== -1) { users[index] = { ...users[index], ...updates, id }; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(users[index])); } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Usuario no encontrado' })); } } catch (err) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'JSON inválido' })); } }); } // DELETE /api/users/:id - Eliminar usuario else if (path.match(/^/api/users/d+$/) && method === 'DELETE') { const id = parseInt(path.split('/')[3]); const index = users.findIndex(u => u.id === id); if (index !== -1) { users.splice(index, 1); res.writeHead(204); res.end(); } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Usuario no encontrado' })); } } // Ruta no encontrada else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Ruta no encontrada' })); } }); const PORT = 3000; server.listen(PORT, () => { console.log(`Servidor API ejecutándose en http://localhost:${PORT}`); }); ``` ## Códigos de Estado HTTP Códigos de estado comunes: | Código | Significado | Uso | |--------|------------|-----| | **200** | OK | Solicitud exitosa | | **201** | Created | Recurso creado | | **204** | No Content | Éxito sin contenido | | **400** | Bad Request | Solicitud inválida | | **401** | Unauthorized | Autenticación requerida | | **403** | Forbidden | Acceso denegado | | **404** | Not Found | Recurso no encontrado | | **500** | Internal Server Error | Error del servidor | ## Mejores Prácticas 1. **Usar Express**: Para aplicaciones reales, usa frameworks como Express 2. **Manejo de Errores**: Siempre manejar errores apropiadamente 3. **Validación**: Validar entrada del usuario 4. **Códigos de Estado**: Usar códigos de estado HTTP correctos 5. **Seguridad**: Implementar límites de tasa, validación, sanitización 6. **CORS**: Configurar CORS apropiadamente para APIs 7. **Logging**: Registrar solicitudes y errores ## Recursos - [Documentación del módulo http](https://nodejs.org/docs/latest/api/http.html) - [Códigos de Estado HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) Para aplicaciones de producción, considera usar Express.js, que simplifica mucho estas tareas! 🚀

Continúa Aprendiendo