Présentation du protocole HTTP/2

Le protocole HTTP/2 rendra nos applications plus rapides, plus simples et plus robustes, une combinaison rare, en nous permettant d'annuler de nombreuses solutions de contournement HTTP/1.1 précédemment mises en œuvre dans nos applications et de répondre à ces préoccupations au sein de la couche de transport. Qui plus est, cela ouvre un certain nombre de nouvelles opportunités d'optimiser nos applications et d'améliorer les performances.

Les principaux objectifs de HTTP/2 sont de réduire la latence en activant le multiplexage complet des requêtes et des réponses, de réduire la surcharge du protocole via une compression efficace des champs d'en-tête HTTP, et d'ajouter la prise en charge de la hiérarchisation des requêtes et du serveur push. Pour mettre en œuvre ces exigences, il existe un large éventail d'autres améliorations de protocole, telles que de nouveaux mécanismes de contrôle de flux, de gestion des erreurs et de mise à niveau. Toutefois, il s'agit des fonctionnalités les plus importantes que tout développeur Web doit comprendre et exploiter dans ses applications.

HTTP/2 ne modifie en aucune façon la sémantique d'application de HTTP. Tous les concepts fondamentaux, tels que les méthodes HTTP, les codes d'état, les URI et les champs d'en-tête, restent en place. Au lieu de cela, HTTP/2 modifie la façon dont les données sont formatées (encadrées) et transférées entre le client et le serveur, qui gèrent tous deux l'intégralité du processus, et masque toute la complexité de nos applications au sein de la nouvelle couche de cadre. Par conséquent, toutes les applications existantes peuvent être livrées sans modification.

Pourquoi pas HTTP/1.2 ?

Pour atteindre les objectifs de performances définis par le groupe de travail HTTP, HTTP/2 introduit une nouvelle couche de frame binaire qui n'est pas rétrocompatible avec les anciens serveurs et clients HTTP/1.x. D'où l'augmentation de la version majeure du protocole en HTTP/2.

Cela dit, à moins que vous n'implémentiez un serveur Web (ou un client personnalisé) en travaillant avec des sockets TCP bruts, vous ne verrez aucune différence: toutes les nouvelles cadres de bas niveau sont effectuées par le client et le serveur en votre nom. Les seules différences observables seront l'amélioration des performances et la disponibilité de nouvelles fonctionnalités telles que la hiérarchisation des requêtes, le contrôle de flux et le transfert de serveur.

Bref historique de SPDY et HTTP/2

SPDY était un protocole expérimental développé par Google et annoncé mi-2009. Son objectif principal était de tenter de réduire la latence de chargement des pages Web en résolvant certaines des limites de performances bien connues du protocole HTTP/1.1. Plus précisément, les objectifs du projet décrits ont été définis comme suit:

  • Ciblez une réduction de 50% du temps de chargement des pages (PLT).
  • éviter d'avoir à modifier le contenu par les auteurs de sites Web.
  • Réduisez la complexité du déploiement et évitez les modifications de l'infrastructure réseau.
  • Développez ce nouveau protocole en partenariat avec la communauté Open Source.
  • Recueillir des données de performances réelles pour (in)valider le protocole expérimental

Peu de temps après l'annonce initiale, Mike Belshe et Roberto Peon, tous deux ingénieurs logiciels chez Google, ont partagé leurs premiers résultats, leur documentation et le code source de la mise en œuvre expérimentale du nouveau protocole SPDY:

Jusqu'à présent, nous n'avons testé SPDY que dans des conditions de laboratoire. Les premiers résultats sont très encourageants: lorsque nous téléchargeons les 25 principaux sites Web via des simulations de connexions à un réseau domestique, nous constatons une amélioration significative des performances (les pages se chargent jusqu'à 55% plus vite). (blog Chromium)

En 2012, le nouveau protocole expérimental était pris en charge dans Chrome, Firefox et Opera, et un nombre croissant de sites, petits ou grands (par exemple, Google, Twitter ou Facebook) et de petite taille, déployaient SPDY dans leur infrastructure. En effet, SPDY était en passe de devenir une norme de facto grâce à son adoption croissante dans le secteur.

Constatant cette tendance, le groupe de travail HTTP (HTTP-WG) a lancé une nouvelle initiative pour tirer les enseignements du SPDY, le développer et l'améliorer, et fournir une norme "HTTP/2" officielle. Une nouvelle charte a été rédigée, un appel ouvert à des propositions HTTP/2 a été fait et après de nombreuses discussions au sein du groupe de travail, la spécification SPDY a été adoptée comme point de départ du nouveau protocole HTTP/2.

Au cours des années suivantes, SPDY et HTTP/2 ont continué à coopérer en parallèle, SPDY jouant le rôle de branche expérimentale utilisée pour tester de nouvelles fonctionnalités et propositions pour la norme HTTP/2. Ce qui semble bon sur le papier peut ne pas fonctionner en pratique, et inversement. SPDY a proposé un moyen de tester et d'évaluer chaque proposition avant son inclusion dans la norme HTTP/2. Au bout du compte, ce processus a duré trois ans et a abouti à plus d'une douzaine de versions intermédiaires:

  • Mars 2012: appel à propositions pour HTTP/2
  • Novembre 2012: premier brouillon de HTTP/2 (basé sur SPDY)
  • Août 2014: publication des brouillons HTTP/2 17 et HPACK 12
  • Août 2014: dernier appel du groupe de travail pour HTTP/2
  • Février 2015: approbation des brouillons HTTP/2 et HPACK par l'IESG
  • Mai 2015: publication des documents RFC 7540 (HTTP/2) et RFC 7541 (HPACK)

Début 2015, l'IESG a examiné et approuvé la nouvelle norme HTTP/2 pour la publication. Peu de temps après, l'équipe Google Chrome a annoncé son calendrier d'arrêt des extensions SPDY et NPN pour TLS:

Les principales modifications apportées par HTTP/2 par rapport à HTTP/1.1 sont axées sur l'amélioration des performances. Certaines fonctionnalités clés, telles que le multiplexage, la compression des en-têtes, la hiérarchisation et la négociation de protocole, sont issues du travail effectué dans un protocole ouvert, mais non standard, appelé SPDY. Chrome est compatible avec SPDY depuis Chrome 6, mais comme la plupart des avantages sont présents dans HTTP/2, il est temps de dire au revoir. Nous prévoyons de supprimer la compatibilité avec SPDY début 2016 et de supprimer en même temps la compatibilité avec l'extension TLS nommée NPN au profit d'ALPN dans Chrome. Nous recommandons vivement aux développeurs de serveurs de passer à HTTP/2 et à ALPN.

Nous sommes heureux d'avoir contribué au processus de normes ouvertes qui a conduit au protocole HTTP/2 et nous espérons une adoption généralisée compte tenu de l'engagement général du secteur concernant la standardisation et l'implémentation. (Blog Chromium)

La coévolution entre SPDY et HTTP/2 a permis aux développeurs de serveurs, de navigateurs et de sites d'acquérir une expérience pratique du nouveau protocole au fur et à mesure de son développement. Par conséquent, la norme HTTP/2 est l'une des meilleures et des plus testées dès le départ. Au moment où HTTP/2 a été approuvé par l'IESG, il y avait des dizaines d'implémentations client et serveur minutieusement testées et prêtes pour la production. En fait, à peine quelques semaines après l'approbation du protocole final, de nombreux utilisateurs en profitaient déjà, car plusieurs navigateurs courants (et de nombreux sites) ont déployé une compatibilité complète avec HTTP/2.

Objectifs techniques et de conception

Les versions précédentes du protocole HTTP ont été intentionnellement conçues pour simplifier l'implémentation: HTTP/0.9 était un protocole en une ligne pour amorcer le World Wide Web, HTTP/1.0 documentait les extensions populaires de HTTP/0.9 dans une norme d'information, et HTTP/1.1 a introduit une norme officielle de l'IETF ; consultez la page Bref historique de HTTP. En tant que tel, HTTP/0.9-1.x répondait exactement à son objectif: HTTP est l'un des protocoles d'application les plus largement adoptés sur Internet.

Malheureusement, la simplicité de l'implémentation a également eu un impact sur les performances de l'application: les clients HTTP/1.x doivent utiliser plusieurs connexions pour obtenir la simultanéité et réduire la latence, HTTP/1.x ne compresse pas les en-têtes de requête et de réponse, ce qui entraîne un trafic réseau inutile, HTTP/1.x ne permet pas de hiérarchiser efficacement les ressources, ce qui entraîne une mauvaise utilisation de la connexion TCP sous-jacente, etc.

Ces limites n'étaient pas fatales, mais à mesure que la portée, la complexité et l'importance des applications Web continuaient à croître dans notre vie quotidienne, elles pesaient de plus en plus sur les développeurs et les utilisateurs du Web, ce qui correspond exactement à l'écart que HTTP/2 a été conçu pour combler:

Le protocole HTTP/2 permet une utilisation plus efficace des ressources réseau et une latence réduite en introduisant une compression des champs d'en-tête et en autorisant plusieurs échanges simultanés sur la même connexion. Plus précisément, il permet d'entrelacer les messages de requête et de réponse sur la même connexion et utilise un codage efficace pour les champs d'en-tête HTTP. Il permet également de hiérarchiser les requêtes, ce qui permet aux requêtes plus importantes de se terminer plus rapidement, ce qui améliore davantage les performances.

Le protocole résultant est plus convivial pour le réseau, car moins de connexions TCP peuvent être utilisées par rapport à HTTP/1.x. Cela se traduit par une concurrence réduite avec d'autres flux et par des connexions plus longues, ce qui se traduit par une meilleure utilisation de la capacité disponible du réseau. Enfin, HTTP/2 permet également un traitement plus efficace des messages grâce à l'utilisation de l'encadrement de messages binaires. (Protocole de transfert hypertexte version 2, brouillon 17)

Il est important de noter que HTTP/2 étend, et non remplace, les normes HTTP précédentes. La sémantique d'application du protocole HTTP est identique. Aucune modification n'a été apportée à la fonctionnalité proposée ni aux concepts fondamentaux tels que les méthodes HTTP, les codes d'état, les URI et les champs d'en-tête. Ces modifications étaient explicitement hors de champ d'application de l'effort HTTP/2. Cela dit, bien que l'API de haut niveau reste la même, il est important de comprendre comment les modifications de bas niveau répondent aux limitations de performances des protocoles précédents. Jetons un coup d'œil au calque de cadrage binaire et à ses caractéristiques.

Couche de cadrage binaire

Au cœur de toutes les améliorations de performances de HTTP/2 se trouve la nouvelle couche de cadrage binaire, qui détermine la manière dont les messages HTTP sont encapsulés et transférés entre le client et le serveur.

Couche de cadre binaire HTTP/2

La "couche" fait référence à un choix de conception visant à introduire un nouveau mécanisme d'encodage optimisé entre l'interface de socket et l'API HTTP supérieure exposée à nos applications: la sémantique HTTP, telle que les verbes, les méthodes et les en-têtes, n'est pas affectée, mais la façon dont ils sont encodés en transit est différente. Contrairement au protocole HTTP/1.x en texte brut délimité par un retour à la ligne, toute la communication HTTP/2 est divisée en messages et trames plus petits, chacun encodé au format binaire.

Par conséquent, le client et le serveur doivent utiliser le nouveau mécanisme d'encodage binaire pour se comprendre: un client HTTP/1.x ne comprend pas un serveur utilisant uniquement HTTP/2, et inversement. Heureusement, nos applications n'ont pas conscience de tous ces changements, car le client et le serveur effectuent toutes les opérations de cadrage nécessaires pour notre compte.

Flux, messages et frames

L'introduction du nouveau mécanisme de cadrage binaire modifie la façon dont les données sont échangées entre le client et le serveur. Pour décrire ce processus, familiarisez-vous avec la terminologie HTTP/2:

  • Flux: flux bidirectionnel d'octets au sein d'une connexion établie, qui peut transporter un ou plusieurs messages.
  • Message: séquence complète de trames mappées à une requête ou à un message de réponse logiques.
  • Trame: la plus petite unité de communication dans HTTP/2, chacune contenant un en-tête de trame, qui identifie au minimum le flux auquel appartient la trame.

La relation entre ces termes peut être résumée comme suit:

  • Toutes les communications sont effectuées sur une seule connexion TCP pouvant transporter un nombre illimité de flux bidirectionnels.
  • Chaque flux possède un identifiant unique et des informations de priorité facultatives permettant de transmettre des messages bidirectionnels.
  • Chaque message est un message HTTP logique, tel qu'une requête ou une réponse, composé d'une ou de plusieurs trames.
  • La trame est la plus petite unité de communication qui porte un type spécifique de données, par exemple, les en-têtes HTTP, la charge utile du message, etc. Les trames de différents flux peuvent être entrelacées, puis réassemblées via l'identifiant de flux intégré dans l'en-tête de chaque trame.

Flux, messages et trames HTTP/2

En résumé, HTTP/2 décompose la communication via le protocole HTTP en un échange de trames encodées en binaire, qui sont ensuite mappées à des messages appartenant à un flux particulier, qui sont tous multiplexés au sein d'une seule connexion TCP. C'est cette base qui permet toutes les autres fonctionnalités et optimisations de performances fournies par le protocole HTTP/2.

Multiplexage des requêtes et des réponses

Avec HTTP/1.x, si le client souhaite effectuer plusieurs requêtes parallèles pour améliorer les performances, plusieurs connexions TCP doivent être utilisées (voir Utiliser plusieurs connexions TCP). Ce comportement est une conséquence directe du modèle de diffusion HTTP/1.x, qui garantit qu'une seule réponse peut être fournie à la fois (mise en file d'attente des réponses) par connexion. Pire encore, cela entraîne également un blocage en tête de ligne et une utilisation inefficace de la connexion TCP sous-jacente.

La nouvelle couche de cadrage binaire dans HTTP/2 supprime ces limites et permet le multiplexage complet des requêtes et réponses, en permettant au client et au serveur de décomposer un message HTTP en trames indépendantes, de les entrelacer, puis de les réassembler à l'autre extrémité.

Multiplexage des requêtes et réponses HTTP/2 dans une connexion partagée

L'instantané enregistre plusieurs flux en cours de transfert au sein de la même connexion. Le client transmet une trame DATA (flux 5) au serveur, tandis que le serveur transmet une séquence entrelacée de trames au client pour les flux 1 et 3. Par conséquent, trois flux parallèles sont en cours.

La possibilité de décomposer un message HTTP en trames indépendantes, de les entrelacer, puis de les réassembler à l'autre extrémité constitue l'amélioration la plus importante du protocole HTTP/2. De fait, elle introduit de nombreux avantages en termes de performances sur l'ensemble de la pile de toutes les technologies Web, ce qui nous permet d'effectuer les opérations suivantes:

  • Entrelacer plusieurs requêtes en parallèle sans bloquer l'une d'entre elles
  • Entrelacer plusieurs réponses en parallèle sans bloquer l'une d'entre elles
  • Utilisez une seule connexion pour envoyer plusieurs requêtes et réponses en parallèle.
  • Supprimez les solutions de contournement HTTP/1.x inutiles (consultez la section Optimisation pour HTTP/1.x, telles que les fichiers concaténés, les sprites d'images et la segmentation de domaine).
  • Réduisez les temps de chargement des pages en éliminant les latences inutiles et en améliorant l'utilisation de la capacité disponible du réseau.
  • Et bien plus encore...

La nouvelle couche de cadrage binaire dans HTTP/2 résout le problème de blocage en tête de ligne rencontré dans HTTP/1.x et élimine la nécessité d'utiliser plusieurs connexions pour permettre le traitement et la diffusion en parallèle des requêtes et des réponses. De ce fait, le déploiement de nos applications est plus rapide, plus simple et plus économique.

Priorisation des flux

Une fois qu'un message HTTP peut être divisé en plusieurs trames individuelles et que nous autorisons le multiplexage des trames de plusieurs flux, l'ordre dans lequel les trames sont entrelacées et livrées à la fois par le client et le serveur devient un facteur de performances critique. Pour faciliter ce processus, la norme HTTP/2 autorise chaque flux à être associé à une pondération et à une dépendance:

  • Chaque flux peut se voir attribuer une pondération entière comprise entre 1 et 256.
  • Chaque flux peut recevoir une dépendance explicite par rapport à un autre flux.

La combinaison des dépendances de flux et des pondérations permet au client de construire et de communiquer un "arbre de priorisation" qui exprime la manière dont il préfère recevoir des réponses. Le serveur peut ensuite utiliser ces informations pour prioriser le traitement par flux en contrôlant l'allocation du processeur, de la mémoire et d'autres ressources. Une fois les données de réponse disponibles, l'allocation de bande passante permet de garantir une distribution optimale des réponses prioritaires au client.

Dépendances de flux et pondérations de flux HTTP/2

Une dépendance de flux dans HTTP/2 est déclarée en référençant l'identifiant unique d'un autre flux comme son parent. Si l'identifiant est omis, le flux dépend du "flux racine". La déclaration d'une dépendance de flux indique que, si possible, des ressources doivent être allouées au flux parent avant ses dépendances. En d'autres termes, "Veuillez traiter et transmettre la réponse D avant la réponse C".

Les flux qui partagent le même parent (en d'autres termes, des flux frères) doivent se voir allouer des ressources proportionnellement à leur pondération. Par exemple, si la pondération du flux A est de 12 et que la pondération de son frère unique B est de 4, déterminez la proportion des ressources que chacun de ces flux doit recevoir:

  1. Somme de toutes les pondérations: 4 + 12 = 16
  2. Divisez chaque pondération de flux par la pondération totale: A = 12/16, B = 4/16

Ainsi, le flux A doit recevoir les trois quarts des ressources disponibles et le flux B un quart des ressources disponibles. Le flux B doit recevoir un tiers des ressources allouées au flux A. Passons à d'autres exemples pratiques dans l'image ci-dessus. De gauche à droite :

  1. Ni le flux A, ni le flux B ne spécifient de dépendance parent et sont dits dépendants du "flux racine" implicite ; A a une pondération de 12 et B une pondération de 4. Ainsi, en fonction de pondérations proportionnelles, le flux B doit recevoir un tiers des ressources allouées au flux A.
  2. Le flux D dépend du flux racine ; C dépend du flux D. Ainsi, D devrait recevoir l'allocation complète des ressources avant C. Les pondérations sont sans conséquence car la dépendance de C communique une préférence plus forte.
  3. Le flux D doit recevoir une allocation complète des ressources avant le flux C ; le flux C doit recevoir l'allocation complète des ressources avant les éléments A et B ; le flux B doit recevoir un tiers des ressources allouées au flux A.
  4. Le flux D doit recevoir une allocation complète des ressources avant E et C ; E et C doivent recevoir une allocation égale avant A et B ; A et B doivent recevoir une allocation proportionnelle en fonction de leurs pondérations.

Comme le montrent les exemples ci-dessus, la combinaison des dépendances de flux et des pondérations fournit un langage expressif pour la hiérarchisation des ressources, ce qui est une fonctionnalité essentielle pour améliorer les performances de navigation lorsque nous disposons de nombreux types de ressources avec des dépendances et des pondérations différentes. Mieux encore, le protocole HTTP/2 permet également au client de mettre à jour ces préférences à tout moment, ce qui permet des optimisations supplémentaires dans le navigateur. En d'autres termes, nous pouvons modifier les dépendances et réaffecter les pondérations en réponse aux interactions de l'utilisateur et à d'autres signaux.

Une connexion par origine

Avec la mise en place du nouveau mécanisme de cadrage binaire, HTTP/2 n'a plus besoin de plusieurs connexions TCP avec des flux multiplex en parallèle. Chaque flux est divisé en plusieurs trames, qui peuvent être entrelacées et priorisées. Par conséquent, toutes les connexions HTTP/2 sont persistantes et une seule connexion par origine est requise, ce qui offre de nombreux avantages en termes de performances.

Pour SPDY et HTTP/2, la fonctionnalité tueuse est un multiplexage arbitraire sur un seul canal contrôlé par la congestion à puits. Cela m'étonne à quel point c'est important et à quel point cela fonctionne. L'une des métriques qui me plaît le plus est la fraction de connexions créées qui ne transportent qu'une seule transaction HTTP (et donc faire en sorte que cette transaction supporte tous les frais généraux). Pour HTTP/1, 74% de nos connexions actives ne comportent qu'une seule transaction. Les connexions persistantes ne sont tout simplement pas aussi utiles que nous le souhaitons tous. Mais dans HTTP/2, ce chiffre tombe à 25%. C'est un énorme avantage pour réduire les frais généraux. (HTTP/2 est activé dans Firefox, Patrick McManus)

La plupart des transferts HTTP sont courts et intensifs, tandis que le protocole TCP est optimisé pour les transferts de données groupés de longue durée. En réutilisant la même connexion, HTTP/2 peut à la fois utiliser plus efficacement chaque connexion TCP et réduire considérablement la surcharge de protocole globale. En outre, moins de connexions réduisent l'encombrement de la mémoire et du traitement sur l'ensemble du chemin de connexion (c'est-à-dire le client, les intermédiaires et les serveurs d'origine). Cela réduit les coûts opérationnels globaux, et améliore l'utilisation et la capacité du réseau. Par conséquent, le passage à HTTP/2 devrait non seulement réduire la latence du réseau, mais également améliorer le débit et réduire les coûts opérationnels.

Contrôle de flux

Le contrôle de flux est un mécanisme permettant d'empêcher l'émetteur de submerger le récepteur de données qu'il ne souhaite pas ou qu'il ne peut pas traiter. Le récepteur peut être occupé, faire face à une charge importante ou ne souhaiter allouer qu'une quantité fixe de ressources à un flux particulier. Par exemple, le client a peut-être demandé un flux vidéo volumineux à priorité élevée, mais l'utilisateur a mis la vidéo en pause et souhaite désormais suspendre ou limiter sa diffusion à partir du serveur pour éviter de récupérer et de mettre en mémoire tampon des données inutiles. Un serveur proxy peut également avoir des connexions en aval rapides et lentes en amont, et souhaite également réguler la vitesse à laquelle le flux en aval fournit les données à la vitesse en amont pour contrôler l'utilisation de ses ressources, etc.

Les exigences ci-dessus vous rappellent-elles le contrôle de flux TCP ? Ils devraient, car le problème est en réalité identique (voir Contrôle de flux). Toutefois, comme les flux HTTP/2 sont multiplexés au sein d'une seule connexion TCP, le contrôle de flux TCP n'est pas assez précis et ne fournit pas les API nécessaires au niveau de l'application pour réguler la diffusion de flux individuels. Pour résoudre ce problème, HTTP/2 fournit un ensemble de composants de base simples qui permettent au client et au serveur d'implémenter leurs propres contrôles de flux au niveau du flux et de la connexion:

  • Le contrôle de flux est directionnel. Chaque récepteur peut choisir de définir n'importe quelle taille de fenêtre pour chaque flux et l'ensemble de la connexion.
  • Le contrôle de flux est basé sur le crédit. Chaque récepteur annonce sa fenêtre initiale de connexion et de contrôle de flux de flux (en octets), qui est réduite chaque fois que l'expéditeur émet une trame DATA et incrémentée via une trame WINDOW_UPDATE envoyée par le récepteur.
  • Le contrôle de flux ne peut pas être désactivé. Une fois la connexion HTTP/2 établie, le client et le serveur échangent des trames SETTINGS, qui définissent la taille de la fenêtre de contrôle de flux dans les deux sens. La valeur par défaut de la fenêtre de contrôle de flux est définie sur 65 535 octets, mais le récepteur peut définir une taille de fenêtre maximale élevée (2^31-1 octets) et la maintenir en envoyant une trame WINDOW_UPDATE chaque fois que des données sont reçues.
  • Le contrôle de flux est saut par saut, et non de bout en bout. Autrement dit, un intermédiaire peut l'utiliser pour contrôler l'utilisation des ressources et mettre en œuvre des mécanismes d'allocation de ressources basés sur ses propres critères et heuristiques.

HTTP/2 ne spécifie aucun algorithme particulier pour implémenter le contrôle de flux. Au lieu de cela, il fournit les éléments de base simples et diffère l'implémentation au client et au serveur, qui peuvent les utiliser pour mettre en œuvre des stratégies personnalisées pour réguler l'utilisation et l'allocation des ressources, ainsi que pour implémenter de nouvelles fonctionnalités de livraison susceptibles d'améliorer les performances réelles et perçues (voir Vitesse, performances et perception humaine) de nos applications Web.

Par exemple, le contrôle de flux au niveau de la couche d'application permet au navigateur de n'extraire qu'une partie d'une ressource particulière, de mettre la récupération en attente en réduisant la fenêtre de contrôle du flux de flux à zéro, puis de la reprendre ultérieurement. En d'autres termes, elle permet au navigateur d'extraire un aperçu ou de la première analyse d'une image, de l'afficher et de poursuivre d'autres extractions à priorité élevée, puis de reprendre l'exploration une fois le chargement des ressources critiques terminé.

La fonctionnalité Server Push

Une autre nouvelle fonctionnalité puissante de HTTP/2 est la capacité du serveur à envoyer plusieurs réponses pour une seule requête client. Autrement dit, en plus de la réponse à la requête d'origine, le serveur peut transmettre des ressources supplémentaires au client (figure 12-5), sans que le client n'ait à les demander explicitement.

Le serveur lance de nouveaux flux (promesses) pour les ressources push

Pourquoi aurions-nous besoin d'un tel mécanisme dans un navigateur ? Une application Web type comprend des dizaines de ressources, qui sont toutes découvertes par le client en examinant le document fourni par le serveur. Par conséquent, pourquoi ne pas éliminer la latence supplémentaire et laisser le serveur transférer les ressources associées à l'avance ? Le serveur sait déjà de quelles ressources le client aura besoin. Il s'agit de la méthode Server Push.

En fait, si vous avez déjà intégré un élément CSS, JavaScript ou tout autre élément via un URI de données (voir Intégration des ressources), vous disposez déjà d'une expérience pratique du serveur push. En intégrant manuellement la ressource au document, nous la transmettons au client sans attendre que celui-ci la demande. Le protocole HTTP/2 permet d'obtenir les mêmes résultats, mais avec des performances supplémentaires. Les ressources push peuvent être:

  • Mise en cache par le client
  • Réutilisation sur différentes pages
  • Multiplexé avec d'autres ressources
  • Priorisé par le serveur
  • Refusé par le client

INTRODUCTION À L'ENGAGEMENT : PUSH_PROMISE

Tous les flux push du serveur sont initiés via des trames PUSH_PROMISE, qui signalent l'intention du serveur de transmettre les ressources décrites au client et doivent être livrés avant les données de réponse qui demandent les ressources transmises. Cet ordre de distribution est essentiel: le client doit savoir quelles ressources le serveur a l'intention de transférer pour éviter de créer des requêtes en double pour ces ressources. La stratégie la plus simple pour satisfaire à cette exigence consiste à envoyer toutes les trames PUSH_PROMISE, qui ne contiennent que les en-têtes HTTP de la ressource annoncée, avant la réponse du parent (en d'autres termes, les frames DATA).

Une fois que le client reçoit une trame PUSH_PROMISE, il a la possibilité de refuser le flux (via une trame RST_STREAM) s'il le souhaite. (Cela peut se produire, par exemple, lorsque la ressource est déjà dans le cache.) Il s'agit d'une amélioration importante par rapport à HTTP/1.x. En revanche, l'utilisation de l'intégration des ressources, qui est une "optimisation" populaire pour HTTP/1.x, équivaut à un "transfert forcé": le client ne peut pas désactiver la ressource intégrée, l'annuler ni traiter la ressource intégrée individuellement.

Avec HTTP/2, le client conserve le contrôle total de l'utilisation du service push du serveur. Le client peut limiter le nombre de flux transférés simultanément, ajuster la fenêtre initiale de contrôle de flux pour contrôler la quantité de données transférées à la première ouverture du flux, ou désactiver complètement la transmission au serveur. Ces préférences sont communiquées via les trames SETTINGS au début de la connexion HTTP/2 et peuvent être mises à jour à tout moment.

Chaque ressource transférée est un flux qui, contrairement à une ressource intégrée, lui permet d'être multiplexée, hiérarchisée et traitée individuellement par le client. La seule restriction de sécurité, appliquée par le navigateur, est que les ressources transférées doivent respecter la règle d'origine identique: le serveur doit faire autorité pour le contenu fourni.

Compression d'en-tête

Chaque transfert HTTP contient un ensemble d'en-têtes qui décrivent la ressource transférée et ses propriétés. Dans HTTP/1.x, ces métadonnées sont toujours envoyées en texte brut et ajoutent entre 500 et 800 octets de surcharge par transfert, et parfois plusieurs kilo-octets si des cookies HTTP sont utilisés. Pour réduire cette surcharge et améliorer les performances, le protocole HTTP/2 compresse les métadonnées de l'en-tête de requête et de réponse à l'aide du format de compression HPACK qui utilise deux techniques simples, mais puissantes :

  1. Elle permet d'encoder les champs d'en-tête transmis via un code de Huffman statique, ce qui réduit leur taille de transfert individuelle.
  2. Elle nécessite que le client et le serveur maintiennent et mettent à jour une liste indexée des champs d'en-tête déjà vus (en d'autres termes, elle établit un contexte de compression partagé), qui est ensuite utilisée comme référence pour encoder efficacement les valeurs transmises précédemment.

Le codage Huffman permet de compresser les valeurs individuelles lors de leur transfert, et la liste indexée des valeurs transférées précédemment nous permet d'encoder les valeurs en double en transférant des valeurs d'index qui peuvent être utilisées pour rechercher et reconstruire efficacement les clés et les valeurs d'en-tête complètes.

HPACK: compression des en-têtes pour HTTP/2

Autre optimisation, le contexte de compression HPACK consiste en une table statique et dynamique: la table statique est définie dans la spécification et fournit une liste de champs d'en-tête HTTP courants que toutes les connexions sont susceptibles d'utiliser (par exemple, des noms d'en-tête valides). La table dynamique est initialement vide et est mise à jour en fonction des valeurs échangées au sein d'une connexion particulière. Par conséquent, la taille de chaque requête est réduite en utilisant un codage Huffman statique pour les valeurs inédites et en substituant des index aux valeurs déjà présentes dans les tables statiques ou dynamiques de chaque côté.

Sécurité et performances du HPACK

Les premières versions de HTTP/2 et SPDY utilisaient zlib, avec un dictionnaire personnalisé, pour compresser tous les en-têtes HTTP. Cela a permis de réduire de 85% à 88% la taille des données d'en-tête transférées et d'améliorer considérablement la latence du temps de chargement des pages:

Sur le lien DSL à faible bande passante, où le lien d'importation n'est que de 375 Kbit/s, demander la compression de l'en-tête en particulier a permis d'améliorer considérablement le temps de chargement des pages pour certains sites (en d'autres termes, ceux qui ont émis un grand nombre de demandes de ressources). Nous avons constaté une réduction du temps de chargement de page de 45 à 1 142 ms simplement due à la compression de l'en-tête. (livre blanc SPDY, chromium.org)

Cependant, au cours de l'été 2012, une attaque de sécurité "CRIME" a été publiée contre les algorithmes de compression TLS et SPDY, ce qui pourrait entraîner le détournement de session. Par conséquent, l'algorithme de compression zlib a été remplacé par HPACK, qui a été spécialement conçu pour: résoudre les problèmes de sécurité détectés, être efficace et simple à mettre en œuvre correctement, et, bien sûr, permettre une bonne compression des métadonnées de l'en-tête HTTP.

Pour plus d'informations sur l'algorithme de compression HPACK, consultez la page IETF HPACK - Header Compression for HTTP/2.

Complément d'informations