CodeGym /Cursos /Spring REST & MVC /Ciclo de la solicitud HTTP: cliente → respuesta

Ciclo de la solicitud HTTP: cliente → respuesta

Spring REST & MVC
Nivel 2, Lección 0
Disponible

1. Introducción

Si estás empezando en el backend, es muy fácil caer en la «visión de túnel»: ver solo el código del servidor o solo el botón Send en Postman. Pero HTTP es siempre comunicación. Toda comunicación tiene un inicio, un proceso y un fin. Si tienes en mente todo el recorrido de la solicitud, es mucho más fácil entender tanto los estados como las cabeceras y por qué el mismo endpoint responde de forma diferente en distintas situaciones.

Imagina que eres un intérprete en una reunión entre dos personas que no entienden el idioma del otro. Una habla, la otra responde. Es imposible evaluar la calidad de la interpretación si solo escuchas la respuesta pero no la pregunta. Del mismo modo, el desarrollador backend no puede pensar en la API «en el vacío». Para él la unidad básica de la realidad es el par «solicitud → respuesta».

Es importante aceptar también otro pensamiento, no siempre cómodo: el servidor no lee la mente del cliente. El servidor ve solo lo que llegó realmente en la solicitud, y reacciona exactamente a eso. Si el cliente «quería una cosa pero envió otra», el servidor procesará honestamente lo que recibió. No es crueldad, sino un acuerdo del protocolo: el sentido de la solicitud vive en el mensaje, no en la cabeza del remitente.

El contexto general ya está claro. Pasemos ahora a una pregunta más concreta: ¿qué ocurre exactamente cuando el cliente llama a una API? Es útil primero tener en mente todo el ciclo completo — solicitud, procesamiento y respuesta. Entonces el method, los headers, el body y el código de estado dejarán de ser un conjunto de palabras sueltas.

Participantes de HTTP: cliente, servidor y «lo que hay entre ellos»

Cuando se dice «el cliente envió la solicitud al servidor», suena como si hubiera un cable directo entre ellos y nada más. En la realidad entre el cliente y tu aplicación suele haber una capa de «todo lo que hay entre ellos»: red, enrutamiento, a veces proxies, a veces balanceadores, a veces sistemas de seguridad corporativos muy «atentos». Pero lo importante es no perderse: incluso si hay muchos intermediarios, la lógica sigue siendo simple — el cliente forma la solicitud HTTP y el servidor forma la respuesta HTTP.

El cliente puede ser cualquier cosa. Para nuestros propósitos educativos, generalmente es Postman, un archivo .http en el IDE, un navegador o una pequeña utilidad. El servidor en nuestro curso es la aplicación backend (el proyecto transversal) que recibe las solicitudes y responde a ellas. La palabra «servidor» en el lenguaje coloquial a menudo se confunde con «máquina» o «máquina virtual». Usaremos una definición más simple: el servidor es el lado que recibe solicitudes HTTP y devuelve respuestas HTTP.

Para fijar los roles, es útil ver una pequeña tabla:

Rol Qué hace Ejemplos en nuestra realidad
Cliente Formula la solicitud y espera la respuesta Postman, .http, navegador, aplicación móvil
Nuestra aplicación Recibe la solicitud, la procesa, formula la respuesta Task Tracker API (servicio Spring Boot)
«Lo que hay entre ellos» Entrega los mensajes y puede influir en la ruta red, infraestructura, computadora local, proxies corporativos

Observa el detalle importante: el cliente siempre inicia. El servidor no «sale al aire» ni pregunta: «¿Necesitan algo?». El servidor espera. Es el cliente quien inicia la comunicación.

2. Ciclo de vida HTTP: solicitud → procesamiento → respuesta

Cuando dices «llamé al endpoint», describes un evento muy concreto: se fue una solicitud, llegó una respuesta. Ese es el ciclo de vida básico. A veces la respuesta es exitosa, a veces tiene error, pero en cualquier caso el ciclo se cierra con una respuesta (o un intento de responder). Es precisamente esa sencillez la que hace que HTTP sea conveniente para las API aplicativas: siempre puedes imaginar mentalmente el «frame antes» y el «frame después».

Dibujemos esto como una secuencia de acciones. No como una mecánica de red profunda, sino como un diagrama de ingeniería que le resulta suficiente al desarrollador backend:

sequenceDiagram
    participant C as "Cliente (Postman/.http)"
    participant A as "Aplicación backend (Task Tracker API)"

    C->>A: "1) HTTP request (solicitud)"
    A->>A: "2) Procesamiento dentro de la aplicación"
    A-->>C: "3) HTTP response (respuesta)"

El diagrama es deliberadamente «plano»: no muestra el interior de la aplicación. Ahora mismo eso es normal. Nos interesa que el cliente envía un mensaje, la aplicación realiza algún procesamiento, y el cliente recibe un mensaje en respuesta.

En términos prácticos el ciclo de vida se puede describir con tres frases cortas:

1. El cliente envió la solicitud.

2. La aplicación procesó la solicitud.

3. El cliente recibió la respuesta.

Suena casi demasiado simple. Pero es precisamente en esa simplicidad donde se apoya un montón de habilidades reales: desde la depuración hasta el diseño de contratos. Si entiendes con seguridad estos tres pasos, te resultará mucho más fácil no confundir los errores del nivel «el servidor no está arrancado» con «el servidor devolvió 404», no confundir «envié la solicitud» con «envié la solicitud en el formato correcto» y no convertir la API en un juego de adivinanzas.

3. El par request → response en forma de texto

Cuando ya ves el ciclo completo, uno de los hábitos más útiles del desarrollador backend es mirar la solicitud y la respuesta como texto normal, sin magia de interfaces. Las interfaces son convenientes, pero a veces ocultan lo importante: el estado, las cabeceras, el cuerpo vacío, la ausencia de cuerpo. Y es que ya en la primera línea el servidor te cuenta la mitad de la verdad sobre el resultado. Los mensajes HTTP en bruto no son temibles — son simplemente cartas con una estructura clara.

Este es un ejemplo mínimo del par «solicitud-respuesta» (deliberadamente simplificado):

// Solicitud HTTP «en bruto» representada como cadena normal (para ilustrar la idea)
String request = """
        GET /api/v1/tasks HTTP/1.1
        """;

// Respuesta HTTP «en bruto»: primera línea + línea vacía + cuerpo (ejemplo)
String response = """
        HTTP/1.1 200 OK

        [{"id":"42","title":"Write docs"}]
        """;

Incluso si todavía no sabes qué significa 200 OK (o lo sabes vagamente), ya se ve la idea principal: la solicitud y la respuesta son dos entidades separadas. La respuesta tiene su propia primera línea y puede tener cuerpo. La solicitud también tiene su primera línea. Ambas partes «intercambian cartas», no telepatía.

Para sentir más fuertemente que esto es efectivamente un proceso, se puede hacer un método muy básico pero útil:

public class HttpLifecycleDemo {

    // Imprimimos los tres pasos del ciclo de vida — así es más fácil mantener en mente el orden
    static void printLifecycle() {
        System.out.println("1) El cliente envió la solicitud");
        System.out.println("2) La aplicación procesó la solicitud");
        System.out.println("3) El cliente recibió la respuesta");
    }

    public static void main(String[] args) {
        // En el ejemplo «cliente/servidor» son condicionales: solo visualizamos la idea
        printLifecycle();
    }
}

Al ejecutarlo verás:

1) El cliente envió la solicitud
2) La aplicación procesó la solicitud
3) El cliente recibió la respuesta

Sí, es trivial. Pero precisamente en las cosas triviales es donde más se tropieza. En la depuración real estarás constantemente volviendo a la pregunta: «¿Dónde estoy ahora en este ciclo? ¿La solicitud no salió? ¿Salió, pero la respuesta no llegó? ¿Llegó, pero no es la correcta?».

4. Dónde acaba el transporte y empieza el contrato de la API

Dentro de HTTP hay un límite importante: los mensajes se pueden percibir como «transporte», pero para el desarrollador backend inmediatamente se convierten en contrato. El contrato significa que el cliente y el servidor acordaron: una solicitud de cierto tipo conduce a una respuesta de cierto tipo. Ese acuerdo puede estar descrito en documentación, OpenAPI, acuerdos del equipo, tests — pero técnicamente siempre se implementa a través de solicitudes y respuestas.

Desde el punto de vista del ciclo de vida, el contrato comienza exactamente en el momento en que el cliente formó el mensaje y lo envió. El servidor no puede trabajar «por intención» — trabaja por hechos. El contrato termina cuando el cliente recibió la respuesta y puede interpretarla: estado, cabeceras, cuerpo (si lo hay). Eso es todo. El ciclo se cerró, y el cliente puede tomar la decisión de qué hacer a continuación: mostrar datos al usuario, repetir la solicitud, informar de un error.

Hay un pensamiento práctico importante: si no recibiste una respuesta HTTP, posiblemente ni siquiera entraste en el contrato. Por ejemplo, la aplicación no está arrancada, el puerto no está escuchando, la dirección es incorrecta, la red no está disponible — entonces no verás ninguna «respuesta HTTP de contrato». Los principiantes a menudo confunden esto: «Si ya hice la solicitud, ¿por qué el servidor no devolvió el JSON con el error?» El servidor no devolvió nada porque ni siquiera llegaste a él.

Es útil distinguir dos situaciones:

Situación Qué ve el cliente Qué significa
No hay respuesta en absoluto Error de conexión (por ejemplo, Connection refused) No se llegó a la respuesta HTTP
Hay respuesta, pero «no exitosa» Hay una primera línea de respuesta con el estado El ciclo HTTP se completó, simplemente el resultado es ese

Incluso sin profundizar en la red, esta distinción ahorra mucho tiempo en la depuración.

5. Cómo observar el ciclo: Postman y .http

Cuando la gente dice «verifiqué la API», a menudo resulta que solo vieron «en algún lugar apareció el JSON». Pero para entender el ciclo de vida hay que observar todo el intercambio: qué línea de solicitud enviaste, qué salió realmente por el cable, qué respuesta llegó, cuánto tiempo tardó y qué había en la primera línea de la respuesta. Postman y .http no son solo herramientas para «enviar solicitudes», sino tus gafas de laboratorio para no trabajar a ciegas.

Este es un ejemplo de escenario .http que puedes tener junto al proyecto. Ahora no hace falta analizar cada línea — lo importante es ver que la solicitud se puede fijar como texto y reproducir:

### 1) Solicitud de lista de tareas (ejemplo)

# Method + URL — esto es lo que realmente llega al servidor
GET http://localhost:8080/api/v1/tasks

En un archivo .http o en Postman normalmente pones la URL completa, porque la herramienta necesita toda la dirección. Cuando miramos el HTTP en bruto, de esa dirección a menudo solo queda el request-target — por ejemplo, /api/v1/tasks. No es un endpoint diferente, es la misma solicitud, simplemente escrita a un nivel más bajo.

Ejecutas esa solicitud en la herramienta — y obtienes una respuesta. A veces bonita, a veces triste, pero de todas formas una respuesta.

Si quieres «ver la respuesta completa» (especialmente en el terminal), existe un truco clásico: pedirle a la herramienta que muestre la primera línea y las cabeceras. Por ejemplo, curl -i (es opcional; si no te gusta el terminal — simplemente sabe que es posible):

# -i imprime la primera línea y las cabeceras de la respuesta junto con el cuerpo
curl -i http://localhost:8080/api/v1/tasks

Verás la respuesta donde arriba estará la primera línea, luego las cabeceras, luego el cuerpo. Ese es el objeto completo de observación para el ingeniero de backend.

La utilidad más frecuente de esta observación es que dejas de discutir con la realidad. No «me parece que el servidor devolvió...», sino «el servidor devolvió esto: esta es la primera línea, estas son las cabeceras, este es el cuerpo». La programación en general tiene una filosofía útil: menos sentimientos, más evidencias.

6. Mini-historia con el ejemplo de Task Tracker API

Para que el ciclo de vida sea completamente tangible, representemos una mini-historia. Tenemos un cliente (tú en Postman o en .http) y una aplicación (Task Tracker API). Haces una llamada concreta: «quiero la lista de tareas». En el escenario happy-path el panorama ya está claro: el cliente envía la solicitud, el servidor responde con 200 OK y si es necesario devuelve el JSON. Pero es más útil mirar los escenarios contrastantes — en ellos la diferencia entre «hay respuesta con error» y «no hay respuesta en absoluto» se ve más rápidamente.

Imagina ahora que la aplicación por algún motivo no encontró lo que solicitaste (o no soporta esa ruta). Entonces el ciclo de vida sigue siendo el mismo, pero la respuesta será diferente:

// El cliente envió la solicitud a un recurso inexistente (ejemplo)
String request = """
        GET /api/v1/tasks/unknown-id HTTP/1.1
        """;

// El servidor respondió con un estado, incluso si el cuerpo está vacío — el ciclo se cerró
String response = """
        HTTP/1.1 404 Not Found
        """;

Ahora no discutimos cuándo exactamente aparece el 404 ni «quién tiene la culpa». Lo más importante es otra cosa: incluso una respuesta «mala» sigue siendo una respuesta, es decir, el ciclo de vida se completó. El cliente obtuvo un resultado y puede continuar su trabajo correctamente: mostrar el mensaje al usuario, solicitar otro recurso, etc.

Y hay otra situación que a menudo confunde a los principiantes: la aplicación no está arrancada en absoluto. Entonces no verás una respuesta HTTP como tal. El ejemplo es condicional (el texto del error depende de la herramienta):

Failed to connect to localhost port 8080: Connection refused

Y esto también es una parte importante del pensamiento de ingeniería: a veces no «recibiste un error de la API», sino que no pudiste comunicarte en absoluto. Es decir, te quedaste atascado antes de que se completara el ciclo de vida.

7. Errores típicos en la comprensión del ciclo de una solicitud HTTP

Cuando empiezas, muchas ganas de considerar HTTP como una especie de tubo mágico: «envié algo y de algún modo se procesó dentro». Los errores suelen aparecer precisamente porque la magia es demasiado cómoda. A continuación hay algunas trampas típicas en las que caen casi todos, y cómo salir de ellas sin heroísmo.

Error n.° 1: mirar solo el cuerpo de la respuesta e ignorar la «respuesta completa».
Normalmente se ve así: la persona ve el JSON y se alegra, pero no lee la primera línea de la respuesta ni las cabeceras. Luego ocurre una situación donde no hay cuerpo (o es breve), y empieza el pánico: «¿Dónde está mi JSON?!». El hábito es simple: primero siempre mira la respuesta completa — primera línea, cabeceras, cuerpo. El cuerpo no es «toda la respuesta», sino solo una parte de ella.

Error n.° 2: pensar que HTTP «empieza en el código de la aplicación».
El principiante escribe el backend y siente internamente que la solicitud «nace» en el controller (o en algún método). En realidad la solicitud nace en el lado del cliente. Mientras el cliente no haya enviado el mensaje, la aplicación puede estar lista cien veces — el intercambio no comenzará. Esto cambia el estilo de pensamiento: empiezas a pensar «¿qué solicitud llegó?», y no «¿qué método me fue llamado?».

Error n.° 3: confundir «no recibí respuesta» con «recibí una respuesta errónea».
Es una diferencia sutil pero muy práctica. Si recibiste una respuesta con un estado (por ejemplo, 404), significa que tu solicitud llegó y el ciclo de vida se completó. Si recibiste un error de conexión, significa que no llegaste a la respuesta HTTP y hablar del contrato de la respuesta no tiene sentido. Esta confusión a menudo lleva a correcciones extrañas: la gente intenta «manejar el 404», cuando la aplicación simplemente no está arrancada.

Error n.° 4: adentrarse demasiado pronto en los detalles de red.
A veces alguien escucha «solicitud-respuesta» y de inmediato se lanza a «TCP, paquetes, tres apretones de manos, MTU, NAT, puertos...». Es un mundo interesante, pero fácilmente absorbe la atención y no deja que se forme el pensamiento de API. En el nivel actual es más útil mantener el foco en el contrato de los mensajes: qué envió el cliente y qué respondió el servidor. El mundo de la red no va a ningún lado — simplemente no dejes que se convierta en tu primer universo.

1
Tarea
Spring REST & MVC, nivel 2, lección 0
Bloqueada
Esquema de ciclo HTTP en consola
Esquema de ciclo HTTP en consola
1
Tarea
Spring REST & MVC, nivel 2, lección 0
Bloqueada
Respuesta recibida o no
Respuesta recibida o no
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION