HTTP: El protocolo que todo desarrollador web debería conocer - Parte 1
Spanish (Español) translation by Eva Collados Pascual (you can also view the original English article)
HTTP significa protocolo de transferencia de hipertexto. Es un protocolo de nivel de aplicación para la comunicación entre sistemas distribuidos, y es la base de la web moderna. Como desarrollador web, todos debemos tener una fuerte comprensión de este protocolo.
Revisemos este potente protocolo a través de la lente de un desarrollador web. Abordaremos el tema en dos partes. En este primer tutorial, cubriremos los conceptos básicos y describiremos los distintas cabeceras de solicitud y respuesta. En el artículo que seguirá a este, revisaremos partes concretas de HTTP, es decir, el almacenamiento en caché, el control de conexiones y la autenticación.
Aunque mencionaré algunos detalles relacionados con las cabeceras, es mejor consultar en su lugar el RFC (RFC 2616) para obtener información en profundidad. Voy a señalar partes específicas de la RFC a lo largo del artículo.
Fundamentos de HTTP
HTTP permite la comunicación entre una variedad de hosts y clientes, y admite una combinación de configuraciones de red.
Para hacer esto posible, asume muy poco en relación a un sistema en particular, y no mantiene el estado entre diferentes intercambios de mensajes.
Esto hace que HTTP sea un protocolo sin estado. La comunicación suele tener lugar a través de TCP/IP, pero se puede utilizar cualquier transporte confiable. El puerto predeterminado para TCP/IP es el número 80, pero también pueden utilizarse otros.



Las cabeceras personalizadas también pueden ser creadas y enviadas por el cliente.
La comunicación entre un host y un cliente se produce a través de un par de solicitud/respuesta. El cliente inicia un mensaje de solicitud HTTP, que es enviado a cambio a través de un mensaje de respuesta HTTP. Veremos este par fundamental de mensajes en la siguiente sección.
La versión actual del protocolo es HTTP/1.1, la cual añade algunas características adicionales a la anterior versión 1.0. La más importante de ellas, en mi opinión, incluye conexiones persistentes, codificación de transferencia fragmentada y cabeceras de almacenamiento en caché detalladas. Tocaremos brevemente estas características en este artículo; la explicación en profundidad se proporcionará en la segunda parte.
URLs
En el corazón de las comunicaciones web está el mensaje de solicitud, que se envían a través de localizadores uniformes de recursos (URL). Estoy seguro de que ya estás familiarizado con las URLs, pero para ser exhaustivo, lo incluiré aquí. Las direcciones URL tienen una estructura simple que consta de los siguientes componentes:



El protocolo suele ser http
, pero también puede ser https
para las comunicaciones seguras. El puerto predeterminado es 80
, pero se puede establecer uno explícitamente, como se ilustra en la imagen anterior. La ruta de acceso del recurso es la ruta de acceso local al recurso en el servidor.
Verbos
También hay proxies de depuración web, como Fiddler en Windows y Charles Proxy para OSX.
Las direcciones URL revelan la identidad del host concreto con el que queremos comunicarnos, pero la acción que se debe realizar en el host es especificada a través de verbos HTTP. Por supuesto, existen varias acciones que a un cliente le gustaría que realizase el host. HTTP ha formalizado unos pocos que capturan lo esencial y que son universalmente aplicables a todo tipo de aplicaciones.
Estos verbos de solicitud son:
- GET: captura un recurso existente. La dirección URL contiene toda la información necesaria que el servidor necesita para localizar y devolver el recurso.
- POST: crea un nuevo recurso. Las solicitudes POST suelen llevar una carga que especifica los datos para el nuevo recurso.
- PUT: actualiza un recurso existente. La carga puede contener los datos actualizados para el recurso.
- DELETE: elimina un recurso existente.
Los cuatro verbos anteriores son los más populares, y la mayoría de las herramientas y frameworks exponen explícitamente estos verbos de solicitud. PUT
y DELETE
a veces se consideran versiones especializadas del verbo POST
, y pueden ser empaquetados como solicitudes POST
con la carga que contiene la acción exacta: crear, actualizar o eliminar.
Hay algunos verbos menos utilizados que también admite HTTP:
- HEAD: es similar a GET, pero sin el cuerpo del mensaje. Se usa para recuperar las cabeceras del servidor de un recurso determinado, generalmente para comprobar si el recurso ha cambiado, a través de sellos de tiempo.
- TRACE: se utiliza para recuperar los saltos que tarda una solicitud en el viaje de ida y vuelta desde el servidor. Cada proxy intermedio o puerta de enlace inyectaría su IP o nombre DNS en el campo de cabecera
Via
. Esto se puede utilizar con fines de diagnóstico. - OPTIONS: se utiliza para recuperar las capacidades del servidor. En el lado del cliente, se puede utilizar para modificar la solicitud en función de lo que el servidor puede admitir.
Códigos de estado
Con direcciones URL y verbos, el cliente puede iniciar solicitudes al servidor. A cambio, el servidor responde con códigos de estado y cargas de mensajes. El código de estado es importante e indica al cliente cómo interpretar la respuesta del servidor. La especificación HTTP define ciertos rangos de números para tipos específicos de respuestas:
1xx: Mensajes informativos
Todos los clientes HTTP/1.1 deben aceptar el encabezado
Transfer-Encoding
.
Esta clase de códigos se introdujo en HTTP/1.1 y es puramente provisional. El servidor puede enviar un mensaje Expect: 100-continue
, indicándole al cliente que continúe enviando el resto de la solicitud, o a ignorarlo si ya lo ha enviado. Se supone que los clientes HTTP/1.0 ignoran esta cabecera.
2xx: Exitoso
Esto le indica al cliente que la solicitud ha sido procesada correctamente. El código más común es 200 OK. Para una solicitud GET
, el servidor envía el recurso en el cuerpo del mensaje. Hay otros códigos menos utilizados:
- 202 Aceptado: la solicitud fue aceptada pero no se ha podido incluir el recurso en la respuesta. Esto es útil para el procesamiento asincrónico en el lado del servidor. El servidor puede optar por enviar información para la supervisión.
- 204 Sin contenido: no hay ningún cuerpo del mensaje en la respuesta.
- 205 Restablecer contenido: indica al cliente que restablezca su visualización de documento.
- 206 Contenido parcial: indica que la respuesta solo contiene contenido parcial. Las cabeceras adicionales indican el rango exacto y la información de caducidad del contenido.
3xx: Redirección
404 indica que el recurso no es válido y no existe en el servidor.
Esto requiere que el cliente tome medidas adicionales. El caso de uso más común es saltar a una URL distinta para capturar el recurso.
- 301 Movido permanentemente: el recurso se encuentra ahora en una nueva dirección URL.
- 303 Véase otro: el recurso se encuentra de forma temporal en una nueva dirección URL. La cabecera de respuesta
Location
contiene la dirección URL temporal. - 304 No modificado: el servidor ha determinado que el recurso no ha cambiado y el cliente debe utilizar su copia almacenada en caché. Esto se basa en el hecho de que el cliente está enviando
ETag
(Etiqueta de entidad) información que es un hash del contenido. El servidor compara esto con su propiaETag
calculada para comprobar si hay modificaciones.
4xx: Error del cliente
Estos códigos se utilizan cuando el servidor piensa que el error parte del cliente, ya sea solicitando un recurso no válido o realizando una solicitud incorrecta. El código más popular en esta clase es 404 Not Found, con el que creo que todos nos identificamos. 404 indica que el recurso no es válido y no existe en el servidor. El resto de códigos en esta clase incluyen:
- 400 Mala petición: la solicitud está mal formada.
- 401 No autorizado: la solicitud requiere autenticación. El cliente puede repetir la solicitud con la cabecera
Authorization
. Si el cliente ya incluyó la cabeceraAuthorization
, las credenciales eran incorrectas. - 403 Prohibido: el servidor ha denegado el acceso al recurso.
- 405 Método no permitido: verbo HTTP no válido utilizado en la línea de solicitud o el servidor no admite ese verbo.
- 409 Conflicto: el servidor no pudo completar la solicitud porque el cliente está intentando modificar un recurso que es más reciente que el sello de tiempo del cliente. Los conflictos surgen principalmente para las solicitudes PUT durante las ediciones colaborativas en un recurso.
5xx: Error del servidor
Esta clase de códigos se utiliza para indicar un error del servidor al procesar la solicitud. El código de error más utilizado es 500 Error interno del servidor. Los otros en esta clase son:
- 501 No implementado: el servidor aún no admite la funcionalidad solicitada.
- 503 Servicio no disponible: esto podría suceder si un sistema interno en el servidor ha fallado o el servidor está sobrecargado. Normalmente, el servidor ni siquiera responderá y la solicitud agotará el tiempo de espera.
Formatos de mensajes de solicitud y respuesta
Hasta ahora, hemos visto que las URLs, los verbos y los códigos de estado conforman partes fundamentales de un par de solicitud/respuesta HTTP.



Echemos ahora un vistazo al contenido de estos mensajes. La especificación HTTP indica que un mensaje de solicitud o una respuesta tiene la siguiente estructura genérica:
message = <start-line> *(<message-header>) CRLF [<message-body>] <start-line> = Request-Line | Status-Line <message-header> = Field-Name ':' Field-Value
Es obligatorio colocar una nueva línea entre las cabeceras del mensaje y el cuerpo. El mensaje puede contener una o más cabeceras, las cuales se clasifican de forma general en:
- cabeceras generales: que son aplicables tanto para los mensajes de solicitud como para los mensajes de respuesta.
- solicitar cabeceras específicas.
- cabeceras específicas de respuesta.
- cabeceras de entidad.
El cuerpo del mensaje puede contener los datos completos de la entidad, o puede ser fragmentado si se utiliza la codificación fragmentada (Transfer-Encoding: chunked
). Todos los clientes HTTP/1.1 deben aceptar la cabecera Transfer-Encoding
.
Cabeceras genéricas
Hay algunas cabeceras (cabeceras genéricas) que son compartidas por los mensajes de solicitud y respuesta:
general-header = Cache-Control | Connection | Date | Pragma | Trailer | Transfer-Encoding | Upgrade | Via | Warning
Ya hemos visto algunas de estas cabeceras, específicamente Via
y Transfer-Encoding
. Cubriremos Cache-Control
y Connection
en la segunda parte.
El código de estado es importante e indica al cliente cómo interpretar la respuesta del servidor.
- La cabecera
Via
se utiliza en un mensaje TRACE y se actualiza por todos los proxies intermitentes y puertas de enlace -
Pragma
es considerada una cabecera personalizada y puede usarse para incluir cabeceras específicas de implementación. La directiva pragma más utilizada esPragma: no-cache
, que realmente esCache-Control: no-cache
bajo HTTP/1.1. Esto se tratará en la Parte 2 del artículo. - El campo
Date
de la cabecera se utiliza para marcar el mensaje de solicitud/respuesta con una sello del tiempo -
Upgrade
se utiliza para cambiar los protocolos y permitir una transición suave a un protocolo más reciente. -
Transfer-Encoding
se utiliza generalmente para dividir la respuesta en partes más pequeñas con el valorTransfer-Codification: chunked
. Esta es una nueva cabecera en HTTP/1.1 y permite la transmisión de respuesta al cliente en sustitución de una carga grande.
Cabeceras de entidad
Los mensajes de solicitud y respuesta también pueden incluir cabeceras de entidad para proporcionar metainformación sobre el contenido (también conocido como Message Body o Entity). Estas cabeceras incluyen:
entity-header = Allow | Content-Encoding | Content-Language | Content-Length | Content-Location | Content-MD5 | Content-Range | Content-Type | Expires | Last-Modified
Todos las cabeceras con prefijo Content-
proporcionan información sobre la estructura, la codificación y el tamaño del cuerpo del mensaje. Algunas de estas cabeceras deben estar presentes si la entidad forma parte del mensaje.
La cabecera Expires
indica un sello de tiempo que indica cuándo expira la entidad. Curiosamente, una entidad "nunca caduca" se envía con un sello de tiempo de un año adelante. La cabecera Last-Modified
indica el último sello de tiempo de modificación de la entidad.
Las cabeceras personalizadas también pueden ser creadas y enviadas por el cliente; serán tratadas como cabeceras de entidad por el protocolo HTTP.
Esto es realmente un mecanismo de extensión, y algunas implementaciones cliente-servidor pueden optar por comunicarse específicamente a través de estas cabeceras de extensión. Aunque HTTP admite cabeceras personalizadas, lo que realmente busca son las cabeceras de solicitud y respuesta, algo que vamos a tratar a continuación.
Formato de solicitud
El mensaje de solicitud tiene la misma estructura genérica que la anterior, excepto para la línea de solicitud que tiene el siguiente aspecto:
Request-Line = Method SP URI SP HTTP-Version CRLF Method = "OPTIONS" | "HEAD" | "GET" | "POST" | "PUT" | "DELETE" | "TRACE"
SP
es el separador de espacio entre los tokens. HTTP-Version
se especifica como "HTTP/1.1" y después va seguido de una nueva línea. Por lo tanto, un mensaje de solicitud típico podría tener el siguiente aspecto:
GET /articles/http-basics HTTP/1.1 Host: www.articles.com Connection: keep-alive Cache-Control: no-cache Pragma: no-cache Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Observa como la línea de solicitud va seguida de muchas cabeceras de solicitud. La cabecera Host es obligatoria para los clientes HTTP/1.1. Las solicitudes GET no tienen un cuerpo de mensaje, pero las solicitudes POST pueden contener los datos de entrada en el cuerpo.
Las cabeceras de solicitud actúan como modificadores del mensaje de solicitud. La lista completa de cabeceras de solicitud conocidas no es demasiado larga y la proporcionamos a continuación. Las cabeceras desconocidas se tratan como campos de cabecera de entidad.
request-header = Accept | Accept-Charset | Accept-Encoding | Accept-Language | Authorization | Expect | From | Host | If-Match | If-Modified-Since | If-None-Match | If-Range | If-Unmodified-Since | Max-Forwards | Proxy-Authorization | Range | Referer | TE | User-Agent
Las cabeceras con prefijo Accept
indican los tipos de medios, idiomas y conjuntos de caracteres aceptables por el cliente. From
, Host
, Referer
y User-Agent
identifican los detalles sobre el cliente que inició la solicitud. Las cabeceras con prefijo If-
se utilizan para hacer que una solicitud sea más condicional y el servidor devuelve el recurso solo si la condición se cumple. De lo contrario, devuelve un 304 Not Modified
. La condición se puede basar en un sello de tiempo o un ETag (un hash de la entidad).
Formato de respuesta
El formato de respuesta es similar al mensaje de solicitud, excepto la línea de estado y las cabeceras. La línea de estado tiene la siguiente estructura:
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
- La versión HTTP se envía como
HTTP/1.1
- El código de estado es uno de los muchos estados discutidos anteriormente.
- La frase de motivo es una versión legible del código de estado.
Una línea de estado típica para una respuesta correcta podría tener ese aspecto:
HTTP/1.1 200 OK
Las cabeceras de respuesta también son bastante limitadas, y el conjunto completo se muestra a continuación:
response-header = Accept-Ranges | Age | ETag | Location | Proxy-Authenticate | Retry-After | Server | Vary | WWW-Authenticate
-
Age
es el tiempo en segundos desde que se generó el mensaje en el servidor. -
ETag
es el hash MD5 de la entidad y se utiliza para comprobar si hay modificaciones. -
Location
se utiliza cuando se envía una redirección y contiene la nueva dirección URL. -
Server
identifica el servidor que genera el mensaje.
Ha habido mucha teoría hasta este punto, así que no te culparé si sientes los ojos somnolientos. Las siguientes secciones, serán más prácticas y realizaremos una encuesta sobre las herramientas, frameworks y bibliotecas.
Herramientas para ver el tráfico HTTP
Existen una serie de herramientas para supervisar la comunicación HTTP. Aquí, enumeramos algunas de las más populares.
Sin duda, el inspector de Chrome/Webkit es uno de los favoritos entre los desarrolladores web:



También hay proxies de depuración web, como Fiddler para Windows y Charles Proxy para OSX. Mi colega, Rey Bango escribió un excelente artículo sobre este tema.






Para la línea de comandos, disponemos de utilidades como curl, tcpdump y tshark para supervisar el tráfico HTTP.
Uso de HTTP en frameworks y bibliotecas web
Ahora que hemos examinado los mensajes de solicitud/respuesta, es hora de que aprendamos cómo las bibliotecas y los frameworks los exponen en forma de una API. Usaremos ExpressJS for Node, Ruby on Rails y jQuery Ajax como nuestros ejemplos.
ExpressJS
Si estás creando servidores web en NodeJS, es muy probable que hayas considerado ExpressJS. ExpressJS se inspiró originalmente en un framework Ruby Web, llamado Sinatra. Como era de esperar, la API también está igualmente influenciada.
Dado que estamos tratando con un framework del lado del servidor, hay dos tareas principales en relación a los mensajes HTTP:
- Leer fragmentos de URL y cabeceras de solicitud.
- Escribir cabeceras y cuerpos de respuesta
Es crucial comprender HTTP para tener una interfaz limpia, simple y tranquila entre dos puntos finales.
ExpressJS proporciona una API sencilla para hacer precisamente eso. No cubriremos los detalles de la API. En su lugar, proporcionaremos enlaces a la documentación detallada disponible en las guías de ExpressJS. Los métodos de la API se explican por sí mismos en la mayoría de los casos. A continuación se muestra una muestra de la API relacionada con la solicitud:
- req.body: obtener el cuerpo de la solicitud.
- req.query: obtener el fragmento de consulta de la dirección URL.
- req.originalUrl
- req.host: lee el campo cabecera del
Host
. - req.accepts: lee los tipos MIME aceptados en el lado del cliente.
- req.get OR req.header: lee cualquier campo de cabecera que haya sido pasado como argumento.
Al salir al cliente, ExpressJS proporciona la siguiente API de respuesta:
- res.status: establece un código de estado explícito.
- res.set: establece una cabecera de respuesta específica.
- res.send: envia HTML, JSON o un octet-stream.
- res.sendFile: transfiere un archivo al cliente.
- res.render: representa una plantilla de vista rápida.
- res.redirect: redirige a una ruta diferente. Express añade automáticamente el código de redirección predeterminado de 302.
Ruby on Rails
Los mensajes de solicitud y respuesta son en su mayoría los mismos, excepto para las cabeceras de primera línea y mensaje.
En Rails, los módulos ActionController y ActionDispatch proporcionan la API para controlar los mensajes de solicitud y respuesta.
ActionController proporciona una API de alto nivel para leer la dirección URL de la solicitud, representar la salida y redirigir a un punto final diferente. Un punto final (también conocido como "aka route") es controlado como un método de acción. La mayor parte de la información de contexto necesaria dentro de un método de acción se proporciona a través de los objetos request
, response
y params
.
- params: da acceso a los parámetros de URL y datos POST.
- request: contiene información sobre el cliente, las cabeceras y la dirección URL.
- response: se utiliza para establecer cabeceras y códigos de estado.
- render: renderiza vistas expandiendo plantillas.
- redirect_to: redirige a un método de acción o una URL diferente.
ActionDispatch proporciona acceso detallado a los mensajes de solicitud/respuesta, a través de las clases ActionDispatch::Request
y ActionDispatch::Response
. Expone un conjunto de métodos de consulta para comprobar el tipo de solicitud (get?()
, post?()
, head?()
, local?()
). Se puede acceder directamente a las cabeceras de solicitud a través del método request.headers()
.
En el lado de la respuesta, proporciona métodos para establecer cookies()
, location=()
y status=()
. Si te sientes aventurero, también puedes configurar body=()
y omitir el sistema de renderizado de Rails.
jQuery Ajax
Dado que jQuery es principalmente una biblioteca del lado cliente, su API de Ajax proporciona lo contrario a un framework del lado del servidor. En otras palabras, le permite leer mensajes de respuesta y modificar mensajes de solicitud. jQuery expone una API simple a través de jQuery.ajax(settings):
Al pasar un objeto settings
con la devolución de llamada beforeSend
, podemos modificar las cabeceras de solicitud. La devolución de llamada recibe el objeto jqXHR (jQuery XMLHttpRequest) que expone un método, denominado setRequestHeader()
para establecer las cabeceras.
$.ajax({ url: 'http://www.articles.com/latest', type: 'GET', beforeSend: function (jqXHR) { jqXHR.setRequestHeader('Accepts-Language', 'en-US,en'); } });
- El objeto jqXHR también se puede utilizar para leer las cabeceras de respuesta con
jqXHR.getResponseHeader()
. - Si deseas realizar acciones específicas para varios códigos de estado, puedes utilizar la devolución de llamada
statusCode
:
$.ajax({ statusCode: { 404: function() { alert("page not found"); } } });
Resumen
Así que esto resume nuestro rápido recorrido por el protocolo HTTP.
Hemos revisado la estructura de URLs, los verbos y los códigos de estado: los tres pilares de la comunicación HTTP.
Los mensajes de solicitud y respuesta son en su mayoría los mismos, excepto para las cabeceras de primera línea y mensaje. Por último, hemos revisado cómo puedes modificar las cabeceras de solicitud y respuesta en frameworks y bibliotecas web.
Comprender HTTP es crucial para tener una interfaz limpia, simple y tranquila entre dos puntos finales. A mayor escala, también ayuda a diseñar la infraestructura de tu red y proporcionar una gran experiencia a los usuarios finales.
En la segunda parte, ¡revisaremos la gestión de conexiones, la autenticación y el almacenamiento en caché! Hasta luego.
Referencias
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weekly