Video Summary and Transcription
HTTP 3, también conocido como H3, es la última versión del protocolo HTTP con nuevas características relacionadas con el rendimiento. Habilitar HTTP 3 requiere un esfuerzo mínimo y proporciona beneficios significativos, pero limita el control detallado sobre las características de rendimiento. Zero RTT tiene limitaciones debido a razones de seguridad y restricciones en las solicitudes permitidas. La carga y priorización de recursos en HTTP 3 tienen algunos problemas, ya que los navegadores pueden no estar de acuerdo en la importancia de los recursos. Fetch priority permite un control detallado sobre el orden de carga de recursos, y el descubrimiento de recursos puede mejorarse con 103 Early Hints. Web transport proporciona acceso de bajo nivel a las características de QUIC y HTTP3 para casos de uso en tiempo real.
1. Introducción a HTTP 3
Hola, soy Robin Marks y trabajo en Akamai. Hoy, me gustaría hablar sobre HTTP 3, la última versión del protocolo HTTP. HTTP 3, también conocido como H3, tiene muchas nuevas características relacionadas con el rendimiento que lo hacen más eficiente que H2 y TCP. Habilitar HTTP 3 requiere un esfuerzo mínimo y proporciona beneficios significativos. Sin embargo, también limita el control detallado sobre las características de rendimiento, como la API Fetch de JavaScript y la característica zero RTT.
Hola, soy Robin Marks y trabajo en Akamai. Y me gustaría hablarles hoy un poco sobre HTTP 3, que es la última y mejor versión del protocolo HTTP.
Y como pueden ver, es realmente bastante diferente de HTTP 2. Uno de los grandes cambios que ocurrieron fue que ya no usamos TCP debajo. Pero hemos pasado a un nuevo protocolo de transporte llamado QUIC en su lugar. QUIC en sí, que se ejecuta en UDP. Realmente no necesitan conocer todos estos detalles.
Lo principal que necesitan saber para hoy es que QUIC y H3 tienen muchas nuevas características relacionadas con el rendimiento a bordo, cosas que lo hacen bastante más eficiente que H2 y TCP, como tal ayuda a que sus páginas web se carguen bastante más rápido. Ahora, podrían pensar, oh, esto parece interesante, pero probablemente va a ser mucho trabajo para mí, ¿verdad?, para empezar a usar todas estas nuevas características. Bueno, ahí es donde entra la buena noticia. Eso no es cierto. Básicamente, si solo habilitan HTTP 3, que a menudo es solo el cambio de un interruptor, obtienen todas estas características de serie. De hecho, ni siquiera tienen que cambiar nada en sus páginas web para hacer un uso óptimo, siempre que ya estén sintonizados para HTTP 2, que, para ser honestos, después de ocho años, realmente deberían estarlo. Esto debería funcionar bien en HTTP 3 también. Entonces, esto es bastante bueno. Pueden obtener todos los beneficios sin mucho trabajo.
Sin embargo, también hay una desventaja en esto, porque significa que no obtienen mucho control detallado sobre estas nuevas características de performance. Un buen ejemplo de esto es la API Fetch de JavaScript, de la cual probablemente todos saben que realmente solo tienen acceso a la opción superior. No hay forma de decir explícitamente que les gustaría usar HTTP3 en lugar de HTTP2 para una llamada. Esto es algo que el navegador decide por sí mismo basado en algunas heurísticas internas bastante complejas. Así que no pueden pasar como un parámetro de protocolo o no hay fetch HTTP3. Y gracias a Dios la última línea aquí no es algo que hayamos optado por, no una URL HTTPS3 específica. Eso habría sido absolutamente loco. Otro ejemplo de esto es la característica zero RTT. Esta es una de las nuevas características de performance en H3 en que hace que la configuración de la conexión sea un poco más corta. Así que para H2 en TCP, esto normalmente toma tres viajes individuales de ida y vuelta en la red antes de que comiencen a recibir datos HTTP de vuelta. Quick en H3 luego reduce esto a solo dos viajes de ida y vuelta porque Quick puede combinar el transporte y el apretón de manos criptográfico TLS en un viaje de ida y vuelta. Y luego está esta mágica nueva característica llamada zero RTT donde ya pueden hacer una solicitud HTTP 3 y obtener alguna respuesta de vuelta en el primer viaje de ida y vuelta de la conexión que es lo más rápido que podemos hacer. Todo esto suena muy bien pero de nuevo realmente no tienen mucho control sobre si o no, por ejemplo, zero RTT se usa en digamos de nuevo una llamada fetch. No hay forma de habilitar, deshabilitar esto.
2. Limitaciones de Zero RTT
El navegador y el servidor determinan las limitaciones de zero RTT por razones de seguridad. A menudo está limitado en muchas implementaciones y tiene restricciones en los tipos de solicitudes permitidas. La falta de control puede llevar a que el navegador envíe solicitudes incorrectas, lo que resulta en un potencial desperdiciado. Aunque obtienes las características de forma gratuita, no está exento de limitaciones.
Esto es algo que el navegador elige por ti. Y en este caso no es solo el navegador, también es el servidor el que va a guiarte. Por algunas complejas razones relacionadas con la seguridad, zero RTT a menudo está bastante limitado en muchas implementaciones. Entonces, por ejemplo, el code que tengo aquí dice que solo puedes usar solicitudes get sin parámetros de consulta en una solicitud de zero RTT. Lo que, como puedes imaginar, realmente reduce la cantidad de casos de uso para los que puedes utilizar esto. Por ejemplo, es bastante inútil para la mayoría de las solicitudes relacionadas con la API. Y de nuevo, porque no tienes mucho control sobre esto, podría ser que el navegador se equivoque. El navegador envía un tipo incorrecto de solicitud en zero RTT. El servidor entonces rechazará eso y el navegador tendrá que intentarlo de nuevo después de ese primer viaje de ida y vuelta. Desperdiciando de alguna manera el potencial de zero RTT. Entonces sí, obtienes todas las características de forma gratuita. Pero no es tan increíble como podría parecer.
3. Carga y Priorización de Recursos
Quiero hablar sobre cómo cargamos recursos individuales en una página y cómo priorizamos cuándo deben cargarse. HTTP 3 utiliza un mecanismo simple para asignar prioridades a los recursos, pero hay algunos problemas con este enfoque. Los navegadores pueden no estar de acuerdo en la importancia de los recursos, y su priorización puede diferir de lo que los desarrolladores esperan.
Ahora, por supuesto, no quiero hablar solo de las cosas que no puedes hacer con H3. Quiero hablar de las cosas que puedes hacer. Entonces, el navegador de alguna manera te protege de estos detalles internos. El protocolo es una especie de caja negra. Pero te ofrece estas características de nivel un poco más alto que puedes usar para ajustar algunos de estos comportamientos. Y me gustaría hablar de algunos de estos contigo hoy.
El primero va a ser sobre cómo cargamos recursos individuales en una página y cómo priorizamos cuándo deben cargarse. Como probablemente sabes, HTTP 2 y también H3 utilizan solo una única conexión de red para cargar todos los recursos. Esto significa que necesitamos decidir de alguna manera en qué orden se cargan realmente los recursos en esa única conexión. Podrías pensar en una solución muy ingenua que va a cargarlos en el orden en que aparecen en el HTML pero eso sería bastante inflexible en la práctica. Y también puedes ver que hay muchas opciones diferentes en las que podrías decidir enviar estos recursos. No tiene que ser necesariamente secuencial de principio a fin.
Entonces, ¿qué sucede en la práctica? ¿Quién decide cómo se hace esto? Bueno, estos son, por supuesto, los navegadores. Para cada solicitud que hace el navegador va a asignar lo que se llama una prioridad. Una indicación de la importancia del recurso cuando debe cargarse. Al menos en HTTP 3 este es un mecanismo muy simple. Es solo un encabezado de solicitud HTTP con un nombre muy predecible: prioridad. Incluso puedes ver esto en las herramientas de desarrollo del navegador. Una prioridad tiene solo dos parámetros. Un parámetro de urgencia que es más o menos un número que indica la importancia y luego incremental diciendo si este recurso puede mezclarse con data de otros recursos o no. Ahora, los detalles no son muy importantes para nosotros hoy.
Lo que es más importante e interesante es que hay algunos problemas con este enfoque. En primer lugar, los navegadores no necesariamente están de acuerdo en qué recursos deberían ser los más importantes. Y en segundo lugar, incluso si están de acuerdo, podrían llegar a una solución diferente a la que tú, como desarrollador, podrías esperar intuitivamente. Así que veamos algunos ejemplos de esto. Así que miré cómo los navegadores hicieron esta priorización hace un par de meses. Y aquí puedes ver la línea superior. Todos los navegadores están de acuerdo en que HTML es de hecho una prioridad muy alta, bastante importante para cargar una página web. Eso es lógico. Lo mismo para CSS, la línea inferior aquí.
4. Prioridades del Navegador para Fuentes y JavaScript
Los navegadores tienen diferentes prioridades para las fuentes y los archivos JavaScript. Firefox asigna una prioridad media a JavaScript no bloqueante del analizador, mientras que Chrome le da una prioridad de red más baja. Safari asigna una alta prioridad a todo JavaScript, excepto a los archivos etiquetados como async. La precarga de JavaScript en Chrome siempre le asigna una alta prioridad, que puede ser demasiado alta en algunos casos. Una nueva característica llamada fetch priority permite un control más detallado sobre la prioridad de los recursos.
Puedes ver que los navegadores coinciden en que es bastante importante. Aunque es un poco más importante en Chrome que en los otros dos. Pero las cosas son muy diferentes para las fuentes. Por ejemplo, a Firefox realmente no le importa tus fuentes personalizadas del departamento de marketing, que es algo opuesto a lo que hace Chrome, que asigna la máxima prioridad posible a las fuentes. Así que ya hay grandes diferencias aquí.
Veamos lo que hacen para JavaScript, porque JavaScript tiene muchas formas diferentes de cargar archivos JavaScript. Veamos primero a Chrome y Firefox. Si tienes un JavaScript en el head, que bloquea el analizador, es decir, se carga de forma sincrónica, eso va a ser una alta prioridad en ambos. Pero luego las cosas difieren. Entonces Firefox dice para cualquier otro tipo de JavaScript, realmente no me importa, simplemente voy a asignarles a todos la prioridad media. Chrome es un poco más detallado, dice, ya sabes, si los etiquetas como async o defer, hazlos no bloqueantes para el analizador, esto en realidad va a hacer que tengan una prioridad más baja en la red también. Ahora podría estar equivocado, pero supongo que lo que esperas como desarrollador es probablemente lo que está haciendo Chrome, ¿verdad? Async y defer son señales claras de que estos recursos son un poco menos importantes que el JavaScript que bloquea el analizador. Así que tiene sentido, pero ahora agárrate a tus asientos porque veamos lo que hace Safari con esto.
En caso de que no esté claro, Safari básicamente dice, realmente no me importa donde se mencione el JavaScript en el HTML, simplemente voy a darle a todo una alta prioridad, no importa si está en el head o en el fondo, todo es lo mismo para mí. La única excepción es si lo etiquetas como async, por alguna razón eso se reduce a la prioridad media, lo cual fue una sorpresa para mí porque hubiera esperado que eso ocurriera con defer, no con async. Y realmente no sé por qué Safari está haciendo esto. Y esto ya es interesante, hagámoslo un poco peor. Introduzcamos la opción de precarga. ¿Qué pasa si pre-cargas un archivo JavaScript? Lo que puedes ver aquí es que para Safari y Firefox, no importa mucho, mantienen sus prioridades estándar para el recurso pre-cargado también. Pero para Chrome, realmente depende de qué archivo JavaScript estás pre-cargando porque siempre le asigna una alta prioridad. Así que digamos por ejemplo, si pre-cargas un JavaScript que está etiquetado como async o defer en Chrome, en realidad estás aumentando considerablemente su prioridad demasiado alta. A veces esto podría ser algo que quieres. Por ejemplo, un buen caso de uso allí es como un gestor de consentimiento de cookies que necesitamos en Europa donde no quieres que sea bloqueante de paquetes. Así que a menudo lo etiquetas como async, pero quieres que se descargue bastante rápido para mostrar el pop-up de cookies a los usuarios. En ese caso, esto podría ser lo que quieres, pero también puedo imaginar bastantes otros casos de uso donde no quieres que la prioridad aumente si pre-cargas JavaScript. Así que necesitamos un control un poco más detallado. Y afortunadamente, recientemente se introdujo una nueva característica que nos permite hacer justamente eso. Esto se llama fetch priority. Y con eso, puedes ajustar un poco la prioridad. No puedes decir literalmente uno de esos cinco niveles pero puedes decir que sea un poco más o un poco menos de lo que el navegador asignaría inicialmente.
5. Prioridad de Fetch y Descubrimiento de Recursos
Puedes usar la prioridad de fetch para controlar el orden de carga de diferentes llamadas de fetch. Actualmente solo está disponible en Chrome pero se implementará en Safari y Firefox. El descubrimiento de recursos puede mejorarse utilizando 103 Early Hints, que permite al navegador descubrir recursos antes de que se genere el HTML.
Entonces, por ejemplo, aquí si pre-cargas defer, puedes decir, solo quiero pre-cargarlo. No quiero aumentar la prioridad. Mantén la prioridad de fetch baja. Y esto no es solo para JavaScript o pre-cargas. También puedes usar esto, por ejemplo, para cargar imágenes. Por ejemplo, tu imagen de pintor de contenido más grande podría tener una alta prioridad de fetch. Y hay muchos otros casos de uso. Diría que léelos en el enlace web.dev que está debajo en la diapositiva.
Ahora un caso especial que quiero mencionar es, de nuevo, la API de fetch. Fetch es un poco raro porque puedes fetch muchos tipos diferentes de recursos. Pero internamente el navegador ve esto siempre como el mismo tipo, siempre el tipo fetch. Como puedes ver de nuevo, los navegadores realmente no están de acuerdo en cuán importantes deberían ser las llamadas de fetch. Ahora esto es un poco molesto porque, digamos que tienes una aplicación JavaScript compleja donde tienes múltiples fetches paralelos al mismo tiempo. Algunos de esos podrían ser claramente de mayor importancia para la lógica de tu aplicación que otros. Y entonces podrías querer decir que esos necesitan ser cargados primero, pero no puedes hacer esto con un fetch normal aparentemente. Afortunadamente, fetch por supuesto también soporta la prioridad de fetch. Está en el nombre, ¿verdad? Sin embargo, no se llama prioridad de fetch. Se llama simplemente prioridad cuando lo usas. Y por ejemplo aquí puedes realmente bajar la prioridad de algunos de tus fetches. Debería ser realmente bastante poderoso si haces una lógica de carga de recursos muy detallada. Esto está actualmente solo en Chrome, pero se está implementando tanto en Safari como en Firefox. Así que llegará a un navegador cerca de ti muy pronto.
Pero la segunda cosa de la que quería hablarles es el descubrimiento de recursos. Por supuesto, solo podemos priorizar los recursos que hemos identificado como necesarios. Ahora, normalmente, sabes, ¿cómo descubre el navegador las cosas? Está en el HTML. Así que si el HTML tarda en generarse, si tenemos un alto tiempo hasta el primer byte, toda la carga de la página también se va a ralentizar porque los recursos se descubren tarde. ¿No sería genial entonces, si pudiéramos hacer algo como esto, donde podríamos hacer que el navegador descubra los recursos mucho antes, incluso antes de que llegue cualquier HTML? Suena mágico, ¿verdad? Esta es en realidad una característica que puedes usar en algunas configuraciones, incluso hoy. Esto se llama 103 Early Hints. Ahora, la configuración que estoy usando aquí hoy, el ejemplo es que estamos usando un servidor de borde, ¿verdad? CDN algo como CloudFlare o Akamai, o si eres muy moderno, Vercel o Netlify. Esto significa que el navegador se conectará al servidor de borde.
6. Obtención y Precarga del Servidor de Borde
Si el servidor de borde no tiene el HTML en caché, lo obtiene del origen. Durante este tiempo, el servidor de borde puede enviar de vuelta 103 Early Hints, que es una lista de enlaces. El navegador puede comenzar a precargar estos archivos, por lo que cuando llega el HTML, el navegador ya tiene archivos críticos. También es posible la precarga y preconexión a dominios de terceros.
Y si el servidor de borde no tiene, digamos, el HTML en caché, necesita ir a buscarlo desde el origen. Mientras eso sucede, el servidor de borde puede enviar de vuelta a 103 Early Hints. Y lo que es, es realmente solo una lista de enlaces. Esto es realmente, de nuevo, solo precargas y preconexiones. Usualmente pondrías esos en el HTML, pero por supuesto, aún no tenemos el HTML. Estamos esperando que se genere. Así que aquí, simplemente ponemos estos en los encabezados de respuesta HTTP directamente. Lo que entonces sucede, el navegador recibe estos enlaces y puede comenzar a precargar estos archivos. De modo que para cuando el HTML realmente llega desde el origen, el navegador ya debería tener grandes partes de tus archivos más críticos. Así es como sucede esta magia, y se pone aún mejor porque incluso puedes precargar y preconectar a dominios de terceros también.
7. Dominio Estático y Renderizado del lado del Servidor
Puedes abrir una nueva conexión a un dominio estático y cargar más recursos mientras esperas el HTML. Esto depende de la generación lenta de HTML, que es más común con el renderizado del lado del servidor. Sugiero volver al renderizado del lado del servidor y abandonar el renderizado del lado del cliente.
Digamos, por ejemplo, que tienes un dominio estático en el que solías alojar algunos activos como fuentes. Mientras todo lo demás está sucediendo, mientras estás esperando el HTML, en paralelo, ya puedes abrir una nueva conexión al otro dominio y cargar más recursos. Así que esto es realmente bastante poderoso, pero como puedes ver, realmente depende de tener un tiempo de generación de HTML bastante lento, que por supuesto va a suceder principalmente si usas algo como el renderizado del lado del servidor y no tanto el renderizado del lado del cliente. ¿Estoy abogando por que todos simplemente nos movamos en masa de vuelta al renderizado del lado del servidor, abandonemos completamente el renderizado del lado del cliente? Bueno, sí, eso es exactamente lo que estoy sugiriendo. Estoy sugiriendo que todos simplemente volvamos a full PHP, olvidémonos completamente del JavaScript. Probablemente eso no es lo que esperabas escuchar en una conferencia de JavaScript, pero ¿qué puedo decir? Soy de la vieja escuela.
8. Introducción a Web Transport
Web Transport es una opción poderosa para casos de uso en tiempo real, proporcionando acceso de bajo nivel a las características de QUIC y HTTP3. Te permite elegir algoritmos de control de congestión, enviar datagramas no confiables y acceder a flujos HTTP3 brutos. Cuando se combina con las próximas características web como WebAssembly y WebCodecs, permite un procesamiento y renderizado de datos eficientes. Sin embargo, WebTransport puede retroceder a HTTP 2 si HTTP 3 está bloqueado, y el navegador abstrae algunos detalles. En general, HTTP 3 ofrece características de alto nivel y posibilidades emocionantes, incluyendo 103 Early Hints y Web Transport.
Ahora, lo último de lo que quería hablarles es algo llamado Web Transport. He hablado un poco sobre la API Fetch, y eso es usualmente la mayoría de lo que necesitas, pero para algunos casos de uso, especialmente algunos casos de uso en tiempo real, necesitas un poco más de poder. Y hasta ahora, tendrías que usar algo como web sockets sobre TCP o si realmente necesitabas UDP o data no confiable, podrías usar algo como el canal de data WebRTC para esto. Ambos funcionan, pero especialmente el último es un poco difícil de usar. No es muy intuitivo configurarlo, especialmente en un contexto de cliente a servidor.
Con HTTP3 y QUIC, ahora tenemos una tercera opción en esta lista, que se llama Web Transport. Y me gusta decir, aunque no es completamente correcto, me gusta decir que Web Transport es lo más cercano que vamos a llegar a un socket de red crudo en el navegador. Como sabrán, no hay sockets TCP o UDP debido a razones de seguridad, pero Web Transport expone la mayoría de las características de bajo nivel de QUIC y HTTP3 de una manera relativamente fácil de usar. Así que, por ejemplo, Web Transport aún no está terminado. Este es el diseño actual, puede cambiar, pero ya te da una idea de los poderes que podrías tener. Por ejemplo, incluso podrías ser capaz de elegir el algoritmo de control de congestión que el navegador usaría, donde podrías ajustar para un alto rendimiento o baja latencia. De manera similar, algo que ves ahí es algo llamado datagramas. Realmente puedes enviar datagramas completamente no confiables. Estos no son datagramas UDP crudos. Estos son en realidad parte de la conexión QUIC, por lo que están completamente encriptados y controlados por flujo y congestión, pero aún así deberían ser muy interesantes para casos de uso como juegos en tiempo real y transmisión de medios. Y finalmente, tienes acceso a los flujos HTTP3 brutos usando una interfaz, creo, muy intuitiva para cualquiera que haya usado otros tipos de flujos de JavaScript.
Así que Web Transport está llegando. Aún no está terminado, pero puedes probar esto en Firefox y Chrome en este momento. Realmente sólo comienza a brillar, sin embargo, cuando lo combinas con otras características web próximas y existentes. Por ejemplo, mucha gente está usando esto para reproducir el caso de uso de WebRTC, transmisión de medios en vivo, pero de una manera mucho más de bajo nivel donde obtienes los data a través de, por ejemplo, Web Transport. Luego puedes usar algo como WebAssembly para procesar los data de manera muy eficiente. Luego hay algo nuevo llamado WebCodecs que realmente te permite decodificar o transcodificar los data de medios de una manera muy eficiente directamente desde JavaScript o WebAssembly. Luego puedes renderizarlo. Y hay ejemplos dentro de un proyecto llamado MediaOverQuick. Están trabajando en un nuevo protocolo específicamente para esto que tiene algunos resultados realmente asombrosos para video de muy baja latencia directamente en el navegador sin toda la complejidad de WebRTC. Así que WebTransport es realmente sólo un bloque de construcción para muchos casos de uso interesantes en la parte superior.
Por supuesto, siempre hay una trampa. Podrías haber visto esto en una de las diapositivas anteriores. No es HTTP 3 crudo porque algunas redes bloquearán activamente o no permitirán HTTP 3 en la práctica. Así que WebTransport retrocederá a HTTP 2 si no está disponible. Y al menos por ahora, el plan es darte acceso a datagramas incluso en HTTP 2 aunque no sean realmente no confiables. Así que, ya sabes, algo a tener en cuenta de nuevo. El navegador abstrae algo de esto a veces un poco demasiado. Con eso, es hora de concluir esto. Creo que está claro que HTTP 3 es de hecho un protocolo muy poderoso. Aunque no puedes hacer mucho de él, hay algunas características de alto nivel que puedes usar. Algunas de ellas son bastante complejas como la priorización y dependen del navegador, pero otras deberían permitir muchos casos de uso nuevos e interesantes como por ejemplo, 103 Early Hints y especialmente Web Transport. Con eso, diría si te gustaría saber más sobre esto o cómo todo era mejor en los buenos viejos días de PHP, avísame y nos vemos la próxima vez.
Comments