33 - Construyendo un web server en Rust desde cero - parte 2 rutas y manejo de peticiones

33 - Construyendo un web server en Rust desde cero - parte 2 rutas y manejo de peticiones

¡Bienvenidos de nuevo a Rustaceo.es! En la primera parte, construimos un servidor básico capaz de recibir conexiones y responder con un mensaje estático. Ahora, llevaremos nuestro Servidor Pokémon al siguiente nivel añadiendo manejo de rutas y procesamiento de peticiones HTTP.


📌 Objetivos de esta parte #

  1. Manejar rutas dinámicas: Responder según la URL solicitada.
  2. Procesar métodos HTTP: Diferenciar entre GET, POST, etc.
  3. Devolver respuestas apropiadas: HTML, JSON o mensajes dinámicos.

🔄 Añadiendo rutas básicas #

Actualmente, nuestro servidor responde con un mensaje estático. Modifiquemos manejar_conexion para procesar rutas y responder adecuadamente.

use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::fs;

fn manejar_conexion(mut stream: TcpStream) {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    
    let request = String::from_utf8_lossy(&buffer[..]);
    let primera_linea = request.lines().next().unwrap_or("");
    let ruta = primera_linea.split_whitespace().nth(1).unwrap_or("/");
    
    let (status_line, contenido) = match ruta {
        "/" => ("HTTP/1.1 200 OK", fs::read_to_string("index.html").unwrap_or("<h1>Bienvenido al Servidor Pokémon</h1>".to_string())),
        "/item1" => ("HTTP/1.1 200 OK", "<h1>Item1 está listo para la batalla!</h1>".to_string()),
        _ => ("HTTP/1.1 404 NOT FOUND", "<h1>404 - Pokémon no encontrado</h1>".to_string()),
    };

    let response = format!("{}\r\n\r\n{}", status_line, contenido);
    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    println!("Servidor Pokémon escuchando en http://127.0.0.1:7878");
    
    for stream in listener.incoming() {
        let stream = stream.unwrap();
        manejar_conexion(stream);
    }
}

🔍 Explicación del código #

  • request.lines().next(): Extraemos la primera línea de la solicitud HTTP.
  • split_whitespace().nth(1): Obtenemos la ruta solicitada.
  • Manejo de rutas:
    • / responde con un archivo index.html o un mensaje por defecto.
    • /item1 responde con un mensaje sobre Item1.
    • Cualquier otra ruta devuelve un error 404.

🌐 Extender el manejo de métodos http #

Por ahora, solo estamos manejando GET. Agreguemos una condición para manejar POST.

let metodo = primera_linea.split_whitespace().nth(0).unwrap_or("GET");
match (metodo, ruta) {
    ("GET", "/") => { /* ... */ }
    ("POST", "/capturar") => ("HTTP/1.1 200 OK", "¡Has capturado un Pokémon!".to_string()),
    _ => ("HTTP/1.1 404 NOT FOUND", "404 - No encontrado".to_string()),
}

Esto permitirá manejar métodos POST, lo que será útil en la tercera parte cuando trabajemos con concurrencia y bases de datos.


🚀 ¿Qué sigue? #

Nuestro servidor ahora puede manejar rutas y diferenciar entre métodos HTTP. En la próxima parte, implementaremos manejo de múltiples conexiones simultáneas (multihilo) para mejorar el rendimiento.

¡Nos vemos en la siguiente entrega, Rustaceos!