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?


45

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 prenant beaucoup de 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 avec ( index.html suivi de style.css et image.jpg )

2
Aucune demande ne peut être faite avant que la page Web soit récupérée. Après cela, les requêtes sont effectuées dans l'ordre lors de la lecture du code HTML. Mais cela ne signifie pas qu’une seule demande est faite à la fois. En fait, plusieurs demandes sont effectuées, mais il existe parfois des dépendances entre elles, et certaines doivent être résolues avant que la page puisse être correctement peinte. Les navigateurs se mettent parfois en pause lorsqu'une demande est satisfaite avant d'apparaître pour traiter d'autres réponses, ce qui donne à penser que chaque demande est traitée une par une. La réalité concerne davantage les navigateurs, car ils ont tendance à consommer beaucoup de ressources.
closetnoc

20
Je suis surpris que personne n'ait mentionné la mise en cache. Si j'ai déjà ce fichier, je n'en ai pas besoin.
Corey Ogburn

2
Cette liste pourrait être longue de centaines de fois. Bien que plus courte que l'envoi des fichiers, elle reste loin d'une solution optimale.
Corey Ogburn

1
En fait, je n'ai jamais visité de page Web contenant plus de 100 ressources uniques.
Ahmed

2
@AhmedElsoobky: le navigateur ne sait pas quelles ressources peuvent être envoyées en tant qu'en-tête de ressources en cache sans récupérer d'abord la page elle-même. Ce serait également un cauchemar pour la confidentialité et la sécurité si la récupération d'une page indique au serveur que j'ai une autre page mise en cache, qui est éventuellement contrôlée par une organisation différente de la page d'origine (site Web à locataires multiples).
Lie Ryan

Réponses:


63

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, maintenant les demandes ressemblent à 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é aussi loin que possible sans que la compatibilité avec les versions précédentes ne soit brisée.

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 appelé SPDY, capable de le faire .

Aujourd'hui, à la fois 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 permet d’économiser les allers-retours entre le client et le serveur et d’empêcher les ressources de faible priorité de bloquer les demandes de priorité supérieure.
  • SPDY permet au serveur de transférer activement des ressources au client dont il sait qu’il aura besoin (par exemple, des 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 push serveur.


2
Dang bonne et informée réponse! Les navigateurs Web sont en série par nature et les demandes peuvent être faites assez rapidement. En consultant un fichier journal, vous constaterez que les demandes de ressources sont effectuées assez rapidement une fois le code HTML analysé. C'est ce que c'est. Ce n'est pas un mauvais système, mais pas aussi efficace en termes de code / ressources.
closetnoc

6
Pour mémoire, SPDY n’est pas le Saint Graal. Il fait certaines choses bien, mais introduit d'autres problèmes. Voici un article contenant quelques points sur SPDY.
Jost

3
Je recommande fortement à toute personne intéressée de lire ces critiques dans le lien de @Jost. Cela vous donne une idée de la complexité impliquée dans la détermination de la manière de faire une chose très couramment implémentée, non seulement de mieux en mieux, mais tellement mieux que tout le monde commence à l'utiliser . Il est facile de penser à une amélioration qui améliore quelque peu les choses pour un sous-ensemble relativement important de cas d'utilisation. Améliorer les choses de manière à ce que tout le monde commence à utiliser votre nouveau protocole, car il est tellement préférable que les coûts de modification en valent la peine, est un tout autre problème, qui n'est pas facile à faire.
msouth

11
il aurait dû laisser le travail aux professionnels : s'il l'avait fait, il leur aurait fallu six ans pour élaborer une norme qui serait devenue obsolète le jour de sa publication et bientôt une douzaine de normes concurrentes seraient apparues. En outre, les professionnels ont-ils besoin de la permission de quelqu'un? Pourquoi ne l'ont-ils pas fait eux-mêmes?
Shantnu Tiwari

2
Pour être franc, il n'y avait pas de professionnels qualifiés à l'époque. Personne ne sait comment créer un réseau mondial, car personne ne l’a jamais construit. Le concept d'hypermédia n'a pas été inventé par Tim. Il avait déjà utilisé dix systèmes hypermédia au niveau local avant de rédiger la proposition de "gestion de l'information" afin de résoudre le problème de la "perte d'informations" au CERN.
Lie Ryan

14

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. Cela s'explique par le fait 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 naviguez sur 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. Cela ressemble à 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 seule connexion, et avec le traitement en pipeline, 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:

rester en vie

pipeline

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, davantage de couches ont été ajoutées à la "spécification de courrier électronique" sous la forme de types MIME supplémentaires, tels que des images, des styles, des scripts, etc. Après tout, MIME signifie Extension de messagerie Internet polyvalente . 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 le navigateur Web à demander les ressources qu'il prend en charge, ce qui satisfait tout le monde et fait progresser la technologie. Un lecteur d'écran a-t-il besoin de tous les JPEG d'une page Web? Probablement pas. Devez-vous être obligé de télécharger un ensemble 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. C'est ce qu'on appelle Rapid Server .

Les références:

Lectures complémentaires:


Eh bien, en fait, nous pouvons nous occuper de tous ces problèmes secondaires (choses telles que: Cache, en-tête Content-Type, etc.), il existe des solutions de contournement pour résoudre ces problèmes. Et comme je l'ai suggéré dans les commentaires sur le post ci-dessus, nous pouvons utiliser quelque chose comme cet en-tête> Cached-Resources: image.jpg; style.css; pour résoudre le problème de la mise en cache .. (Si vous avez le temps, alors vous pouvez jeter un oeil aux commentaires ci-dessus ..)
Ahmed

Oui, cette idée m’avait déjà traversé l’esprit, mais c’est tout simplement trop de travail pour HTTP et cela ne résout pas le fait que les ressources peuvent être réparties sur plusieurs serveurs. En outre, je ne pense pas que votre méthode d'économie de temps proposée permettrait de gagner du temps car les données seront envoyées sous forme de flux, peu importe la façon dont vous le regardez, et avec Keep-Alive, 100 demandes HTTP simultanées deviennent essentiellement une demande. La technologie et les capacités que vous proposez semblent déjà exister d'une certaine manière. Voir en.wikipedia.org/wiki/HTTP_persistent_connection
perry

@perry: Que pensez-vous de l'idée d'une alternative à l' https://envoi de gros fichiers distribués publiquement qui doivent être authentifiés mais ne doivent pas rester confidentiels: incluez dans l'URL un hachage de certaines parties de l'en-tête d'une réponse légitime, ce qui pourrait à son tour inclure une signature ou un hachage de la charge de données et demander aux navigateurs de valider les données reçues par rapport à l'en-tête? Une telle conception permettrait non seulement d’économiser certaines étapes de négociation SSL, mais permettrait surtout de mettre en cache les proxies. Obtenez l'URL via un lien SSL et les données pourraient être alimentées de n'importe où.
Supercat

11

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 demander.

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


2
Surtout si vous utilisez quelque chose comme require.js. Le navigateur demande seulement ce dont il a besoin. Imaginez avoir à tout charger en même temps ...
Aran Mulholland

2
C'est la bonne réponse, et il semble que la plupart des commentateurs manquent à l'appel: pour que le serveur envoie les ressources de manière proactive, il doit savoir ce qu'elles sont, ce qui signifie que le serveur devrait analyser le code HTML.

1
Mais la question demande pourquoi le serveur Web n'envoie pas les ressources, pas pourquoi le client ne peut pas les demander en même temps. Il est très facile d'imaginer un monde où les serveurs disposent d'un ensemble d'actifs liés qui sont tous envoyés ensemble et qui ne reposent pas sur l'analyse HTML pour créer le package.
David Meister

@ DavidMeister Parce que le serveur ne sait pas toujours ce que le client veut - un crawl web pour un moteur de recherche ne se soucie peut-être pas de CSS / JS, et il existe de nombreuses autres ressources liées dans un document au-delà de celles-ci - il n'est pas nécessaire d'envoyer l'intégralité du document. Le flux RSS est envoyé vers un navigateur Web (la plupart du contenu est probablement déjà dans le code HTML), alors qu'un lecteur de flux pourrait simplement analyser l' <head>élément en recherchant les liens alternatifs RSS pour trouver exactement cela: le client pourrait envoyer une liste de ce qui l’intéresse, mais il doit ensuite savoir ce qui est disponible et nous sommes de retour au début
Zhaph - Ben Duguid

@ Zhaph-BenDuguid Je parle d'un monde alternatif, pour souligner que la réponse a autant à voir avec le fonctionnement du protocole qu'avec n'importe quoi d'autre. En outre, il peut être plus rapide pour un serveur d’envoyer toutes les données en même temps, même si cela n’est pas nécessaire. Vous négociez essentiellement les problèmes de latence par rapport à l'utilisation de la bande passante.
David Meister

8

Parce que, dans votre exemple, le serveur Web envoie toujours les fichiers CSS et les images, que le client les possède déjà, gaspillant ainsi beaucoup de bande passante (et ralentissant ainsi la connexion au lieu de la rendre 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 une longue période).

Maintenant, vous pouvez essayer de contourner ce gaspillage de bande passante en disant " OK, mais le client pourrait 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"

Et ensuite, seuls les fichiers qui n'ont pas été modifiés sont envoyés via une seule connexion TCP (à l'aide du traitement en pipeline HTTP via une connexion persistante). Et devine quoi? C'est comme ça que ça fonctionne déjà (vous pouvez aussi 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 <style>et <script>tags (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 à l'aide de l'URI des données , 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 poser de 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 ce qu'il contient (CSS, JavaScript, images) au sein d'un seul code HTML. comme décrit ci-dessus, ajoutez un lien rel = "prefetch" 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 demande 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 supplémentaires CSS + JS + ne seront envoyées que deux fois, même si vous avez cliqué 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’utilisera jamais (ni la première fois ni les suivantes) plus d’ un aller-retour augmentant le temps de latence.

Maintenant, si cela semble trop demander 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 peuvent automatiquement effectuer une partie de ce travail pour vous (fusion de plusieurs fichiers CSS / JS). en une seule, auto-alignant les petites CSS et les minimisant, créant de petites images en attente en attendant le chargement des originaux, un chargement paresseux des images, etc.) sans exiger que vous modifiiez une seule ligne de votre page Web.


3
Je pense que c'est la bonne réponse.
el.pescado

7

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


3

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, compte tenu de ce que vous souhaitez faire avec le fichier . Cela pose trois gros problèmes.

Le premier problème est qu’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 filecommande Unix tentent 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 à prix réduit n'est pas assez robuste.

Le deuxième problème est que l' analyse d'un fichier est coûteuse, en termes 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 voulez 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 constatiez 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 nombreux types d’agents utilisateurs ne nécessitent pas les fichiers référencés dans le code HTML : ils ne vous souciez que du HTML lui-même. L'envoi de ces autres fichiers à ces utilisateurs-agents ne ferait que gaspiller de la bande passante.

L'essentiel est que déterminer ces dépendances côté serveur représente plus de problèmes qu'il n'en vaut la peine . Alors, au lieu de cela, ils laissent le client comprendre ce dont il a besoin.


Si nous développons un nouveau protocole ou si nous corrigeons un protocole existant, nous pouvons régler tous ces problèmes d’une manière ou d’une autre! Et le serveur Web n'analysera les fichiers qu'une seule fois, puis il pourra les classer en fonction de règles définies, de manière à pouvoir hiérarchiser les fichiers à envoyer en premier ... etc et le serveur Web ne doit pas savoir ce que je suis censé faire. avec ces fichiers, il faut juste savoir quoi envoyer, quand faire et en fonction des règles .. (les robots web et les araignées ne posent pas de problème, le comportement sera différent avec eux -ils ont des en-têtes user-agent uniques- ..)
Ahmed

@AhmedElsobky: Ce dont vous parlez ressemble plus à une implémentation spécifique qu'à un protocole réseau. Mais il doit vraiment savoir ce que vous avez l'intention de faire avec les fichiers avant de pouvoir déterminer ce qu'il faut envoyer: sinon, il enverra inévitablement des fichiers que de nombreux utilisateurs ne veulent pas. Vous ne pouvez pas faire confiance aux chaînes User-Agent, vous ne pouvez donc pas les utiliser pour déterminer l'intention de l'utilisateur.
Le Spooniest
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.