====== 02 - Servidor HTTP sobre sockets ====== **HTTP** es un protocolo de aplicación sobre TCP: el cliente envía una **petición** con formato definido y el servidor responde con una **respuesta** también con formato definido. Como el formato es texto, un servidor HTTP puede construirse con los sockets del tema anterior. ===== 1. Formato de una petición ===== GET /books/42 HTTP/1.1 Host: localhost:8080 Accept: application/json * **Línea de petición:** método, ruta y versión. * **Cabeceras:** pares ''Nombre: valor'' (una por línea). * **Línea en blanco:** separa cabeceras y cuerpo (el cuerpo puede estar vacío en un ''GET''). ===== 2. Formato de una respuesta ===== HTTP/1.1 200 OK Content-Type: application/json Content-Length: 39 {"id":42,"title":"Código limpio"} * **Línea de estado:** versión, **código de estado** y frase. * **Cabeceras:** ''Content-Type'', ''Content-Length''... * **Cuerpo:** los datos, en el formato que anuncia ''Content-Type''. ^ Código ^ Significado ^ | ''200'' | OK | | ''201'' | Recurso creado | | ''400'' | Petición mal formada | | ''404'' | No encontrado | | ''500'' | Error del servidor | ===== 3. Servidor mínimo ===== public class HttpServer { public static void main(String[] args) throws IOException { try (ServerSocket serverSocket = new ServerSocket(8080)) { while (true) { try (Socket socket = serverSocket.accept()) { handle(socket); } } } } private static void handle(Socket socket) throws IOException { BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream()); String requestLine = in.readLine(); // GET /books/42 HTTP/1.1 String route = requestLine.split(" ")[1]; readHeaders(in); // hasta la línea vacía String body = "{\"message\":\"Hello from " + route + "\"}"; out.print("HTTP/1.1 200 OK\r\n"); out.print("Content-Type: application/json\r\n"); out.print("Content-Length: " + body.getBytes().length + "\r\n"); out.print("\r\n"); out.print(body); out.flush(); } private static void readHeaders(BufferedReader in) throws IOException { String line; while ((line = in.readLine()) != null && !line.isEmpty()) { // procesar cada cabecera si hace falta } } } Con un navegador o ''curl'' contra ''http://localhost:8080/books/42'' se obtiene la respuesta JSON. ===== 4. Lo que falta ===== ^ Necesidad ^ Solución que llega después ^ | Atender varias peticiones a la vez | **Hilos** (tema siguiente) | | Parsear rutas, parámetros y cuerpos completos | **Servlets** y Tomcat | | Devolver archivos, páginas, errores estándar | El contenedor lo resuelve | Este servidor cumple el protocolo, pero es secuencial: una sola petición a la vez. Es la motivación exacta de por qué los servidores reales usan un pool de hilos.