HTTP-1
Índice
- El comando netcat
- Verbos HTTP
- Encabezados comunes de respuesta
- REST
- Fundamentos básicos de rendimiento
- Detalles de rendimiento
El comando netcat
Netcat es una utilidad que se usa para enviar y recibir mensajes sobre una conexión de red. Netcat es conocida como la navaja suiza de las herramientas de red, y la usaremos para comunicarnos directamenque con un servidor.
Existen muchas variaciones de Netcat, y la que vamos a utilizar es a través del comando nc
. El siguiente comando nos permitirá conectarnos a Google sobre el puerto 80 (El puerto por defecto para las conexiones HTTP)
$ nc google.com 80
Ahora, la terminal espera que ingresemos los detalles de la solicitud HTTP. Para enviar una solicitud GET escribimos:
GET / HTTP/1.1
… luego asegúrese de haber oprimido la tecla enter dos veces (una vez para obtener una nueva línea, y otra más para indicar que ha finalizado de ingresar los encabezados de la solicitud). Así obtendrá una respuesta similar a:
HTTP/1.1 200 OK
Date: Thu, 18 Oct 2018 15:40:47 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2018-10-18-15; expires=Sat, 17-Nov-2018 15:40:47 GMT; path=/; domain=.google.com
Set-Cookie: NID=141=GKRXnxjpycAJYid5E4sZgR3nxZG-QFv4Oga2MdHy_goXSLI9GWyZ-MH71DYX241G7SnUQFPD3EJfym0uj50d4T6ZY9nfdPNhyMPL-SkOoQF1V_oB98kEigKPnz6A20WG; expires=Fri, 19-Apr-2019 15:40:47 GMT; path=/; domain=.google.com; HttpOnly
Accept-Ranges: none
Vary: Accept-Encoding
Transfer-Encoding: chunked
File Itself...
Con este ejemplo, ya sabemos como hacer peticiones HTTP y recibir respuestas HTTP a través del comando nc
.
Verbos HTTP
HTTP ha existido por tanto tiempo que el protocolo todavía hace algo que rara vez encontrará en cualquier protocolo moderno. Tanto las solicitudes como las respuesta es texto regular y puede ser leído por un humano. Los bytes que se transmiten hacia adelante y hacia atrás en la red son texto simple, antiguo y regular, y pueden ser leídos por nuestro cerebro humano.
La simplicidad de HTTP también significa que podemos interactuar directamente con un protocolo sin que una biblioteca de terceros realice ningún trabajo adicional para nosotros.
Cada solicitud HTTP comienza con un verbo único llamado método y sirve para un propósito específico. Hasta ahora hemos visto dos, GET
y POST
y aunque estos son los métodos más comunes, existen otros métodos que usted va encontrar con regularidad. El conjunto común de métodos HTTP son:
GET
POST
PUT
DELETE
HEAD
OPTIONS
Hablaremos de ellos con mayor detalle en la sección de REST APIs.
Ahora, recuerde que las solicitudes comienzan con un método HTTP, la ruta y la versión del protocolo a usar, como se muestra en la siguiente línea:
HEAD / HTTP/1.1
Esta solicitud esta utilizando el método HEAD
. HEAD
es un método interesante, ya que le permite obtener los encabezados de un archivo sin tener que recibir el archivo completo. Esto le permite verificar si hay suficiente espacio para almacenar la respuesta o si la versión almacenada en caché en esa página aún está actualizada. De esta manera el navegador puede evitar volver a descargar un archivo si ya tiene la versión más reciente en su caché.
Al revisar la pestaña Network de las herramientas para desarrolladores de cualquier navegador, es probable que no vea ninguna solicitud HTTP con el método HEAD
cuando esta visitando sus sitios web.
No obstante, el uso del método HEAD
tiene un problema al validar el uso de caché, ya que se esta haciendo un doble trabajo. Al enviar una solicitud HEAD
es probable que reciba otra solicitud inmediatamente después. Por ende, se atiende el par de solicitudes y eso implica más tiempo para completar la respuesta. Con el gran número de accesos que tienen los sitios web hoy e día, tener que enviar las solicitudes HEAD
antes que la solicitud GET
ralentizaría considerablemente la carga del sitio web.
Hay formas de mitigar el costo de estos viajes de ida y vuelta y serán abordados en la sección de rendimiento. Por ahora, es importante saber que queremos que nuestros sitios tengan la menor cantidad posible de viajes. Eso significa reducir la cantidad de solicitudes lo mejor que podamos.
El último método por evaluar es OPTIONS
. Se supone que OPTIONS
le proporciona una lista de los métodos que se aceptan en la URL actual, pero no todos los servidores lo admiten. El método OPTIONS
puede parecer extraño al principio, pero se vuelve importante cuando comenzamos a hablar sobre los temas restantes de este documento.
Encabezados comunes de respuesta
Los encabezados contienen datos adicionales sobre las peticiones y las respuestas. A continuación se citan las mas importantes:
Content-Length
es un encabezado que debe contener cada respuesta y le dice al navegador el tamaño del cuerpo en la respuesta. De esta forma, el navegador sabe cuántos bytes espera recibir después de la sección de encabezado y así mostrar el progreso de la descarga del archivo en la respuesta.Content-Type
también es un encabezado obligatorio e indica que tipo de documento se esta solicitando. De esta manera el navegador sabe que motor de análisis de usar. Si se recibe un.jpeg
se muestra una imagen, si es untext/html
se analiza el documento y se disparan las solicitudes HTTP adicionales necesarias. El navegador toma una acción acorde al tipo de dato que se este usando dentro del protocolo.Last-Modified
es un encabezado que contiene la fecha en que se modifico por última vez el documento. No obstante, este encabezado no es confiable si se quiere averiguar si un documento ha sido cambiado. A veces, los desarrolladores cargan todos los archivos en el servidor después de arreglar algo, restableciendo la fecha de última modificación en todos los archivos a pesar de que el contenido solo se cambio en un subconjunto. Para manejar este inconveniente, la mayoría de los servidores envían uneTag
.eTag
significa etiqueta de entidad y es un identificador único que cambia solo en función del contenido del archivo. Los servidores usan una función hash comoSHA256
para calcular eleTag
Cache-Control
es un encabezado que se explica por si solo. Le permite al servidor controlar cómo y durante cuánto tiempo el cliente almacenará en caché la respuesta que se recibió.Cache-Control
es una bestia compleja y tiene muchas características integradas. Las propiedades más usadas son capacidad del almacenamiento y edad_máxima.If-Modified-Since
permite que el servidor omita el envío del contenido real del documento si no se ha modificado desde la fecha provista en ese encabezado.If-None-Match
es un encabezado que audita la etiquetaeTag
. Si eleTag
para el documento coincide con laetag
enviada en el encabezadoIf-None-Match
, el servidor no enviará el documento real.
Tanto
If-Modified-Since
yIf-None-Match
pueden estar presentes en la misma solicitud. No obstante,eTag
tiene la prioridad sobre estos encabezados ya que se considera más precisa.
A continuación se comparte la lista de todos los encabezados HTTP.
REST
Cuando escriba aplicaciones web, el desarrollador encontrará una cantidad the APIs con las que se va a comunicar. Algunas de ellas pueden ser una API de Javascript que no son más que el llamado a una función en JavaScript. Otras APIs, son proporcionadas por terceros y requieren que usted mismo realice las solicitudes HTTP.
Una API REST sigue un diseño llamado REST (REpresentational State Transfer ) que funciona muy bien con HTTP. Siendo sinceros, el nombre no es muy descriptivo. No todas la API siguen el patrón REST, pero muchas si lo hacen, por tanto es importante profundizar el concepto.
REST es un diseño en donde las entidades básicas son colecciones y objetos dentro de esas colecciones. El patrón general para ejecutar acciones sobre elementos de colecciones requiere del verbo HTTP con el <nombre de la colección>
y el único <nombre de elemento>
en esa colección. A continuación una forma genérica para el consumo de API REST:
<METHOD> <collection_name> /<element_name>
Por ejemplo, si quisiera buscar información de “Link” que esta dentro de una colección de personajes, debe enviar una solicitud GET
y el servidor obtendría el registro que contiene los datos sobre “Link”. La solicitud GET
tendría la siguiente forma:
GET characters /link
Si quisiera actualizar los datos en ese registro, usaría una solicitud PUT
y agregaría la información actualizada a la solicitud. Cada solicitud GET
subsiguiente debería ahora generar el registro actualizado. La solicitud PUT
tendría la siguiente forma:
PUT characters /link /saria
Una solicitud POST
se usa de manera similar a PUT
, pero en lugar de actualizar los registros existentes, la usa para crear nuevos registros. Es este tipo de solicitudes podemos dejar que el servidor proporcione el nombre con el que se creará el registro si dicha información no es suministrada. La respuesta a la solicitud POST
suele ser una redirección al registro recién creado. La solicitud POST
para agregar a la colección de personajes la información de “Zelda” sería la siguiente:
POST characters /zelda
Por último la solicitud DELETE
se explica por si sola, y por ende eliminará elementos de la colección. La solicitud DELETE
tendría la siguiente forma:
DELETE characters /saria
Fundamentos básicos de rendimiento
Ya estamos en capacidad de escribir una solicitud que será dirigida al cable y ya sabemos que recibiremos dos notificaciones, una por parte del servidor que envió la petición y otra por parte del servidor que respondió la solicitud. Como casi no hay software entre este contexto, podemos decir que los bytes ya se están enviando. Sin embargo hay muchas cosas que no podemos ver directamente y tienen un impacto grande sobre la rapidez con la que todo el proceso de respuesta de solicitud se ejecuta. Si está familiarizado con la arquitectura de redes, es consiente de que HTTP no es la historia completa, es simplemente un protocolo.
Para una imagen más completa, estamos usando HTTP
sobre TCP
, sobre IP
, sobre Ethernet
.
- HTTP, Hyper Text Transfer Protocol.
- TCP, Transmission Control Protocol.
- IP, Internet Protocol.
- Ethernet.
El orden de las capas es importante, y la lista se lee desde una transición de Software a Hardware. Siendo 1 el punto de partida del Software y 4 la llegada a Hardware.
No es necesario entender cada una de estas capas, pero TCP
en particular, tiene un gran impacto en la forma en que debemos estructurar nuestra solicitudes para que funcionen bien y por ende merece un análisis detallado.
El IP
nos permite hablar con otras máquinas, mientras que TCP
nos permite tener multiples flujos de datos independientes entre estas dos máquinas. Estás corrientes se distinguen por números de puerto. TCP
, también garantiza que no se pierdan paquetes y que lleguen en el orden correcto. Todo esto requiere precauciones y gastos que cuestan tiempos y recursos.
Abrir una nueva conexión es costoso, ya que el intercambio TCP
debe garantizar que ambas máquinas sean conscientes de que el canal de comunicación recién creado tiene que ejecutarse. Para ello, TCP
establece un intercambio de tres vías: el primer mensaje es emitido por una máquina remitente. El mensaje manifiesta su interés por comunicarse con un máquina receptora. El segundo mensaje es emitido por la máquina receptora y confirma que pudo escuchar el mensaje de la máquina remitente y hace una pregunta para validar si la maquina remitente puede escuchar su mensaje de confirmación. El tercer y último mensaje es emitido por la maquina remitente y confirma que pudo escuchar el mensaje de la máquina receptora, es en este paso donde se consolida la conexión entre las dos máquina a través de TCP
. Una vez hecho todo esto, el protocolo HTTP
puede finalmente tomar el control.
Por último, se resalta un problema de cuello de botella llamado head-of-line blocking que afecta el rendimiento de un sitio web. Este problema se administra con la capacidad que tienen los navegadores de soportar hasta seis conexiones paralelas, pero ya veremos porque esta característica no es suficiente. En la siguiente sección revisaremos con mayor detalle el head-of-line blocking.
Detalles de rendimiento
Para obtener mejoras en el rendimiento de nuestras solicitudes HTTP, es necesario luchar contra la naturaleza pura de la arquitectura web y de red.
Un indicador importante en rendimiento es el TTFB (Time to First Byte). TTFB representa el tiempo de espera desde que se presiona la tecla intro en la barra de direcciones hasta que la página se muestra con una respuesta.
El TTFB puede ser consultado en la pestaña Network de las herramientas para desarrolladores de un navegador.
Si el sitio web necesitara recursos adicionales, se debe esperar la respuesta de la primera solicitud antes de poder enviar una segunda solicitud. Por tanto, tenemos otro periodo de espera correspondiente a la segunda solicitud que no se esta utilizando de manera efectiva. Este problema se llama head-of-line blocking. La siguiente analogía ilustra el head-of-line blocking y su impacto negativo en rendimiento y por ende en la experiencia de usuario.
Con HTTP, una conexión es como una fila. Supongamos, que estamos en una cafetería y hay una fila de personas esperando por hacer su pedido. Mientras la primera persona en la fila esta siendo atendido, todas las otras personas tienen que esperar hasta que sea su respectivo turno. Se esta perdiendo mucho tiempo aquí.
Ahora, la persona que esta de primeras en la fila hace el siguiente pedido:
Me gustaría un café con la siguiente preparación: media taza con leche entera, un cuarto de taza con leche descremada y el cuarto de taza restante con agua caliente. Una cucharada con syrup, tres chispitas de canela un toque de vainilla, dos paquetes de splenda y uno de azúcar normal. Y te recuerdo que tengo un poco de prisa.
Mientras se prepara esta bebida, los otros clientes tienen que esperar a pesar de que su solicitud sea mucho más rápida de atender. El primero en la fila esta bloqueando al resto de los clientes. –head-of-line blocking–.
Para neutralizar un poco esta limitación, los navegadores abren seis conexiones paralelas, o en nuestra analogía de la cafetería, contratan a otro barista. Entonces mientras la primera conexión esta esperando su primer byte, ya se puede enviar una segunda solicitud en la segunda conexión, y así sucesivamente. Por su puesto, contratar a un nuevo barista implica tiempo y entrenamiento.
En el navegador, abrir estas conexiones es bastante costoso debido a los pasos necesarios que se deben hacer para establecer la comunicación con TCP
. Las seis conexiones paralelas que los navegadores pueden habilitar son solo una ayuda de banda para manejar el head-of-line-blocking. Si el sitio web tiene muchos recursos, pasará la mayor parte del tiempo esperando. En la publicación de HTTP/2 explicaremos como esta versión del protocolo soluciona este problema.
Cada vez que el navegador se conecta a un servidor para hacer una solicitud, tiene que pasar por un proceso de reconocimiento TCP
. Este proceso de tres pasos para establecer la conexión TCP
consume mucho tiempo.
Para contrarrestar el costo de estos intercambios, HTTP/1.1
introdujo el concepto de Keep-Alive
. Si el cliente establece el encabezado Keep-Alive
de la conexión, el servidor no cerrará la conexión después de entregar con éxito la respuesta, permitiendo así que el cliente reutilice la conexión ya establecida para solicitudes adicionales.
No obstante, tenga en cuenta que aún puede enviar solicitudes antes de que la respuesta de la última solicitud se haya transferido por completo. En consecuencia, este contexto obliga a los desarrolladores web a mantener un número de recursos adicionales lo más bajo posible, haciendo el mejor uso de sus seis conexiones. Esta es la razón por la que los archivos JavaScript y CSS se concatenan comúnmente en paquetes y las imágenes se juntan en sprites. Los paquetes se pueden obtener en una sola solicitud.
Comentarios finales
HTTP
es la base de la web tal y como la conocemos, y las aproximaciones que se acaban de exponer ayudan a comprender porque las cosas se comportan como lo hacen. Antes de saltar a HTTP/2
, vamos e explorar el cifrado en HTTPS
. HTTPS
es un tema muy mal entendido ya que tiene reputación de ser solo para organizaciones empresariales y sitios de comercio electrónico. Eso definitivamente no es correcto y veremos que es mucho más simple de lo que parece en la siguiente publicación.