Índice

  1. El comando netcat
  2. Verbos HTTP
  3. Encabezados comunes de respuesta
  4. REST
  5. Fundamentos básicos de rendimiento
  6. 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. HEADes 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 un text/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 un eTag. 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 como SHA256 para calcular el eTag
  • 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 etiqueta eTag. Si el eTag para el documento coincide con la etag enviada en el encabezado If-None-Match, el servidor no enviará el documento real.

Tanto If-Modified-Since y If-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.

  1. HTTP, Hyper Text Transfer Protocol.
  2. TCP, Transmission Control Protocol.
  3. IP, Internet Protocol.
  4. 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.