====== 02 - Servidor HTTP ======
===== Servidor HTTP =====
HTTP es un protocolo de aplicación que funciona encima de TCP.
Cuando escribimos un servidor HTTP, en el fondo estamos abriendo un socket TCP, recibiendo la petición y devolviendo una respuesta siguiendo el formato que dicta el protocolo HTTP.
En este caso, vamos a construir un servidor muy básico que:
* Escucha en un puerto con un [[https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/net/ServerSocket.html|ServerSocket]].\\ \\
* Acepta una conexión de un cliente (normalmente un navegador).\\ \\
* Lee la petición HTTP (cabeceras y línea de petición).\\ \\
* Devuelve una respuesta HTTP con código 200 y un pequeño HTML.\\ \\
===== Anatomía de una petición HTTP =====
Cuando un navegador solicita una página, envía algo parecido a:
GET / HTTP/1.1
Host: localhost:12345
User-Agent: Mozilla/5.0 ...
Accept: text/html
[... otras cabeceras ...]
Las cabeceras terminan con una línea vacía (\r\n).
===== Anatomía de una respuesta HTTP =====
El servidor debe responder con:
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: [número de bytes del HTML]
Connection: close
Hola
Las cabeceras también terminan con una línea vacía antes del contenido.
===== Ciclo de vida clásico =====
**Servidor**
* **new ServerSocket(puerto)** → queda “escuchando”.\\ \\
* **accept() (bloqueante)** → devuelve un Socket para el navegador.\\ \\
* Lee la petición (normalmente hasta la línea vacía que separa cabeceras del cuerpo).\\ \\
* Escribe una respuesta que cumpla el protocolo HTTP.\\ \\
* Cierra Socket (y luego ServerSocket si termina).\\ \\
**Cliente (navegador)**
* Abre conexión TCP al host:puerto.\\ \\
* Envía petición HTTP (línea de petición + cabeceras).\\ \\
* Recibe respuesta HTTP y renderiza el HTML.\\ \\
* Cierra conexión.\\ \\
===== Ejemplo =====
**HttpServer**
package es.cesguiro.socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class HttpServer {
private final int port = 12345;
public void start() {
System.out.println("Starting HTTP server on port " + port + "...");
try {
System.out.println("HTTP server started. Waiting for requests...");
// Aceptamos UNA conexión de cliente y luego cerramos el servidor (Ejemplo simple)
try(Socket socket = new ServerSocket(port).accept()) {
System.out.println("Client connected: " + socket.getInetAddress());
// Leer la solicitud HTTP del cliente
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
String line;
while ((line = in.readLine()) != null && !line.isEmpty()) {
System.out.println(line);
}
// HTML a devolver
String htmlResponse = "Hello from HTTP Server!
";
byte[] content = htmlResponse.getBytes(StandardCharsets.UTF_8);
// Cabeceras de respuesta HTTP
String responseHeader = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"Connection: close\r\n" +
"\r\n";
OutputStream out = socket.getOutputStream();
out.write(responseHeader.getBytes(StandardCharsets.UTF_8));
out.write(content);
out.flush();
} catch (IOException e) {
System.err.println("Error handling client connection: " + e.getMessage());
}
} catch (Exception e) {
System.err.println("Error starting HTTP server: " + e.getMessage());
throw new RuntimeException("Failed to start HTTP server", e);
}
}
}
package es.cesguiro.socket;
public class Main {
public static void main(String[] args) {
HttpServer server = new HttpServer();
server.start();
}
}
Para probarlo, accede en tu navegador a http://localhost:12345 y debería ver el mensaje **"Hello from HTTP Server!"**