# 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! 🚀