web-dev-qa-db-fra.com

Lorsque les serveurs Web envoient une page, pourquoi n'envoient-ils pas tous les fichiers CSS, JS et images requis sans qu'on le leur demande?

Lorsqu'une page Web contient un seul fichier CSS et une image, pourquoi les navigateurs et les serveurs perdent-ils du temps avec cet itinéraire traditionnel, qui prend du temps:

  1. le navigateur envoie une requête GET initiale pour la page Web et attend la réponse du serveur.
  2. le navigateur envoie une autre requête GET pour le fichier css et attend la réponse du serveur.
  3. le navigateur envoie une autre requête GET pour le fichier image et attend la réponse du serveur.

Quand au lieu de cela pourraient-ils utiliser cet itinéraire court, direct et rapide?

  1. Le navigateur envoie une demande GET pour une page Web.
  2. Le serveur Web répond par (index.html suivi de style.css et image.jpg)
45
Ahmed

La réponse courte est "Parce que HTTP n'a pas été conçu pour cela".

Tim Berners-Lee n'a pas conçu de protocole réseau efficace et extensible. Son objectif de conception était la simplicité. (Le professeur de ma classe de réseautage à l'université a dit qu'il aurait dû laisser le travail à des professionnels.) Le problème que vous décrivez n'est qu'un des nombreux problèmes du protocole HTTP. Dans sa forme originale:

  • Il n'y avait pas de version de protocole, juste une demande de ressource
  • Il n'y avait pas d'en-tête
  • Chaque demande nécessitait une nouvelle connexion TCP
  • Il n'y avait pas de compression

Le protocole a ensuite été révisé pour résoudre bon nombre de ces problèmes:

  • Les demandes étaient versionnées, elles ressemblent maintenant à GET /foo.html HTTP/1.1
  • Des en-têtes ont été ajoutés pour les méta-informations avec la demande et la réponse.
  • Les connexions ont été autorisées à être réutilisées avec Connection: keep-alive
  • Des réponses en blocs ont été introduites pour permettre la réutilisation des connexions même lorsque la taille du document n'est pas connue à l'avance.
  • La compression Gzip a été ajoutée

À ce stade, HTTP a été utilisé à peu près aussi loin que possible sans pour autant mettre fin à la compatibilité en amont.

Vous n'êtes pas la première personne à suggérer qu'une page et toutes ses ressources soient transmises au client. En fait, Google a conçu un protocole capable de le faire appelé SPDY .

Aujourd'hui, Chrome et Firefox peuvent utiliser SPDY au lieu de HTTP pour les serveurs qui le prennent en charge. Depuis le site Web de SPDY, ses principales caractéristiques par rapport à HTTP sont les suivantes:

  • SPDY permet au client et au serveur de compresser les en-têtes de requête et de réponse, ce qui réduit l'utilisation de la bande passante lorsque des en-têtes similaires (par exemple, des cookies) sont envoyés à plusieurs reprises pour plusieurs requêtes.
  • SPDY autorise plusieurs demandes multiplexées simultanément sur une seule connexion, ce qui réduit les allers-retours entre le client et le serveur et empêche les ressources de faible priorité de bloquer les demandes de priorité supérieure.
  • SPDY permet au serveur de pousser activement des ressources vers le client dont il sait qu’il aura besoin (par exemple, les fichiers JavaScript et CSS) sans attendre que le client les demande, ce qui permet au serveur d’utiliser efficacement la bande passante inutilisée.

Si vous souhaitez que votre site Web avec SPDY soit utilisé par les navigateurs qui le prennent en charge, vous pouvez le faire. Par exemple Apache a mod_spdy .

SPDY est devenu la base de HTTP version 2 avec la technologie serveur Push.

63

Votre navigateur Web ne connaît pas les ressources supplémentaires jusqu'à ce qu'il télécharge la page Web (HTML) à partir du serveur, qui contient les liens vers ces ressources.

Vous vous demandez peut-être pourquoi le serveur n'analyse pas simplement son propre code HTML et n'envoie pas toutes les ressources supplémentaires au navigateur Web lors de la demande initiale de la page Web. C'est parce que les ressources peuvent être réparties sur plusieurs serveurs et que le navigateur Web n'a peut-être pas besoin de toutes ces ressources car il en a déjà mis en cache ou peut ne pas les prendre en charge.

Le navigateur Web conserve un cache de ressources afin qu'il ne soit pas obligé de télécharger sans cesse les mêmes ressources depuis les serveurs qui les hébergent. Lorsque vous parcourez différentes pages d'un site Web qui utilisent toutes la même bibliothèque jQuery, vous ne souhaitez pas télécharger cette bibliothèque à chaque fois, mais pour la première fois.

Ainsi, lorsque le navigateur Web récupère une page Web du serveur, il vérifie les ressources liées qu'il n'a PAS déjà dans le cache, puis effectue des demandes HTTP supplémentaires pour ces ressources. Assez simple, très flexible et extensible.

Un navigateur Web peut généralement faire deux demandes HTTP en parallèle. Ce n'est pas sans ressembler à AJAX - ce sont deux méthodes asynchrones de chargement de pages Web: le chargement de fichier asynchrone et le chargement de contenu asynchrone. Avec keep-alive, nous pouvons faire plusieurs demandes en utilisant une connexion et avec pipelining nous pouvons faire plusieurs demandes sans attendre les réponses. Ces deux techniques sont très rapides car la majeure partie des frais généraux provient généralement de l'ouverture/la fermeture de connexions TCP:

keep-alive

pipelining

Un peu d'histoire web ...

Les pages Web ont débuté sous la forme de courriers électroniques en texte brut, les systèmes informatiques étant conçus autour de cette idée, formant une plate-forme de communication assez libre pour tous; Les serveurs Web étaient encore propriétaires à l'époque. Plus tard, d’autres couches ont été ajoutées à la "spécification email" sous la forme de types MIME supplémentaires, tels que des images, des styles, des scripts, etc. Après tout, MIME signifie Multi-Purpose Internet Mail Extension. Tôt ou tard, nous avons eu essentiellement des communications par courrier électronique multimédia, des serveurs Web normalisés et des pages Web.

HTTP requiert que les données soient transmises dans le contexte de messages de type courrier électronique, bien que le plus souvent, les données ne soient pas réellement des messages électroniques.

À mesure que la technologie évolue, elle doit permettre aux développeurs d’incorporer progressivement de nouvelles fonctionnalités sans compromettre les logiciels existants. Par exemple, lorsqu'un nouveau type MIME est ajouté à la spécification - disons JPEG -, les serveurs Web et les navigateurs Web mettront un certain temps à l'implémenter. Vous ne forcez pas soudainement JPEG dans la spécification et ne commencez pas à l'envoyer à tous les navigateurs Web, vous autorisez celui-ci à demander les ressources qu'il prend en charge, ce qui satisfait tout le monde et permet à la technologie de progresser. Un lecteur d'écran a-t-il besoin de tous les fichiers JPEG d'une page Web? Probablement pas. Devez-vous être obligé de télécharger un tas de fichiers Javascript si votre appareil ne prend pas en charge Javascript? Probablement pas. Googlebot doit-il télécharger tous vos fichiers Javascript pour pouvoir indexer votre site correctement? Nan.

Source: J'ai développé un serveur Web basé sur des événements, tel que Node.js. Cela s'appelle Rapid Server .

Références:

Lectures complémentaires:

14
perry

Parce qu'ils ne savent pas quelles sont ces ressources. Les ressources requises par une page Web sont codées au format HTML. Ce n'est qu'après qu'un analyseur a déterminé quels sont ces actifs que l'utilisateur-agent peut les y demander.

De plus, une fois que ces actifs sont connus, ils doivent être servis individuellement afin que les en-têtes appropriés (c'est-à-dire le type de contenu) puissent être servis afin que l'agent utilisateur sache comment les gérer.

12
John Conde

Parce que, dans votre exemple, le serveur Web enverrait toujours toujours les CSS et les images, que le client les possède déjà, gaspillant ainsi considérablement la bande passante (et établissant ainsi la connexion). plus lent au lieu de plus rapide en réduisant la latence, ce qui était sans doute votre intention). Notez que les fichiers CSS, JavaScript et les fichiers image sont généralement envoyés avec des délais d’expiration très longs pour cette raison (par exemple, lorsque vous devez les modifier, il vous suffit de modifier le nom du fichier pour forcer la nouvelle copie, qui sera à nouveau mise en cache pendant longtemps).

Maintenant, vous pouvez essayer de contourner ce gaspillage de bande passante en disant " OK, mais le client peut indiquer qu'il dispose déjà de certaines de ces ressources, afin que le serveur ne l'envoie pas à nouveau " . Quelque chose comme:

GET /index.html HTTP/1.1
Host: www.example.com
If-None-Match: "686897696a7c876b7e"
Connection: Keep-Alive

GET /style.css HTTP/1.1
Host: www.example.com
If-None-Match: "70b26618ce2c246c71"

GET /image.png HTTP/1.1
Host: www.example.com
If-None-Match: "16d5b7c2e50e571a46"

Ensuite, seuls les fichiers non modifiés sont envoyés via une connexion TCP (en utilisant le traitement en pipeline HTTP sur une connexion persistante). Et devine quoi? Voici comment cela fonctionne déjà (vous pouvez également utiliser If-Modified-Since au lieu de If-None -Match ).


Mais si vous voulez vraiment réduire le temps de latence en gaspillant beaucoup de bande passante (comme dans votre demande initiale), vous pouvez le faire aujourd'hui en utilisant la norme HTTP/1.1 lors de la conception de votre site Web. La plupart des gens ne le font pas parce qu'ils ne pensent pas que cela en vaut la peine.

Pour ce faire, vous n'avez pas besoin d'avoir CSS ou JavaScript dans un fichier séparé, vous pouvez les inclure dans le fichier HTML principal en utilisant les balises <style> et <script> (vous n'avez probablement même pas besoin de le faire manuellement. , votre moteur de template peut probablement le faire automatiquement). Vous pouvez même inclure des images dans le fichier HTML en utilisant data URI , comme ceci:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />

Bien sûr, l’encodage en base64 augmente légèrement l’utilisation de la bande passante, mais si vous ne vous souciez pas de la bande passante gaspillée, cela ne devrait pas être un problème.

Maintenant, si cela vous intéresse, vous pouvez même créer des scripts Web assez intelligents pour tirer le meilleur parti des deux mondes: à la première demande (l'utilisateur ne dispose pas de cookie), envoyez tout (CSS, JavaScript, images) incorporé dans un seul code HTML. fichier comme décrit ci-dessus, ajoutez un link rel = "prefetch" tags pour les copies externes des fichiers, et ajoutez un cookie. Si l'utilisateur a déjà un cookie (par exemple, il l'a déjà visité auparavant), envoyez-lui simplement un code HTML normal avec <img src="example.jpg">, <link rel="stylesheet" type="text/css" href="style.css"> etc.

Ainsi, lors de la première visite, le navigateur ne demande qu’un seul fichier HTML et affiche et affiche tout. Ensuite, il précèderait (lorsqu'il était inactif) les images CSS, JS et externes externes spécifiées. Lors de la prochaine visite de l'utilisateur, le navigateur demandera et obtiendra uniquement les ressources modifiées (probablement uniquement du nouveau HTML).

Les données d'images CSS + JS + supplémentaires ne seraient envoyées que deux fois, même si vous cliquiez des centaines de fois sur le site Web. Beaucoup mieux que des centaines de fois comme suggéré par votre solution proposée. Et il n’utiliserait jamais plus ( un aller-retour plus de temps de latence (ni la première fois ni les suivants).

Maintenant, si cela semble trop de travail et que vous ne voulez pas utiliser un autre protocole tel que SPDY , il existe déjà des modules tels que mod_pagespeed pour Apache, qui peut automatiquement effectuer une partie de ce travail à votre place (fusion de plusieurs fichiers CSS/JS en un seul, auto-alignement des petits CSS et minification de ces derniers, création de petites images insérées en attente pendant le chargement des originaux, chargement paresseux d'images, etc.) sans que vous deviez modifier une seule ligne de votre page Web.

8
Matija Nalis

HTTP2 est basé sur SPDY et fait exactement ce que vous suggérez:

À haut niveau, HTTP/2:

  • est binaire, au lieu de textuel
  • est entièrement multiplexé au lieu d'être commandé et bloquant
  • peut donc utiliser une connexion pour le parallélisme
  • utilise la compression d'en-tête pour réduire les frais généraux
  • permet aux serveurs de "pousser" les réponses de manière proactive dans les caches client

Plus est disponible sur HTTP 2 Faq

7
MaBu

Parce que cela ne suppose pas que ces choses sont réellement nécessaires.

Le protocole ne définit aucun traitement particulier pour un type de fichier ou un agent d'utilisateur particulier. Il ne connaît pas la différence entre, par exemple, un fichier HTML et une image PNG. Pour faire ce que vous demandez, le serveur Web doit identifier le type de fichier, l'analyser pour déterminer quels autres fichiers il référence, puis déterminer quels autres fichiers sont réellement nécessaires, en fonction de vos besoins. l'intention de faire avec le fichier. Cela pose trois gros problèmes.

Le premier problème est que il n’existe aucun moyen standard et robuste d’identification des types de fichiers sur le serveur. HTTP gère via le mécanisme Content-Type, mais cela n'aide pas le serveur, qui doit résoudre ce problème seul (en partie pour qu'il sache quoi mettre dans le type de contenu). Les extensions de nom de fichier sont largement prises en charge, mais fragiles et faciles à duper, parfois à des fins malveillantes. Les métadonnées du système de fichiers sont moins fragiles, mais la plupart des systèmes ne les supportent pas très bien, donc les serveurs ne se dérangent même pas. Le sniffing de contenu (comme certains navigateurs et la commande Unix file essaient de le faire) peut être robuste si vous voulez le rendre coûteux, mais le sniffing robuste est trop coûteux pour être pratique côté serveur, et le sniffing bon marché pas assez robuste.

Le deuxième problème est que l’analyse d’un fichier coûte cher, en terme de calcul. Cela rejoint un peu le premier, dans la mesure où vous auriez besoin d'analyser le fichier de différentes manières si vous souhaitez analyser le contenu de manière robuste, mais cela s'applique également après avoir identifié le type de fichier, car vous avez besoin pour savoir quelles sont les références. Ce n’est pas si grave lorsque vous ne créez que quelques fichiers à la fois, comme le navigateur, mais un serveur Web doit gérer des centaines, voire des milliers de demandes à la fois. Cela s’ajoute, et si cela va trop loin, cela peut réellement ralentir les choses plus que ne le feraient plusieurs demandes. Si vous avez déjà visité un lien provenant de Slashdot ou de sites similaires, mais que vous constatez que le serveur est terriblement lent en raison d'une utilisation intensive, vous avez pu constater ce principe.

Le troisième problème est que le serveur n'a aucun moyen de savoir ce que vous avez l'intention de faire avec le fichier. Un navigateur peut avoir besoin des fichiers référencés dans le code HTML, mais cela n’est peut-être pas le cas, en fonction du contexte exact dans lequel le fichier est exécuté. Cela serait assez complexe, mais le Web ne se limite pas aux seuls navigateurs: entre les spiders, les agrégateurs de flux et les mashups de récupération de page, il existe de nombreux types d’agents d’utilisateur qui n’ont pas besoin des fichiers référencés dans le HTML: ils ne s'intéressent qu'au HTML lui-même. L'envoi de ces autres fichiers à de tels agents utilisateurs ne ferait que gaspiller de la bande passante.

En fin de compte, il est plus difficile de déterminer ces dépendances côté serveur.. Alors, au lieu de cela, ils laissent le client comprendre ce dont il a besoin.

3
The Spooniest