Servant CSS et JavaScript compressés à partir d'Amazon CloudFront via S3

194

Je cherchais des moyens d'accélérer le chargement de mon site et j'aimerais explorer une meilleure utilisation de Cloudfront.

Parce que Cloudfront n'a pas été conçu à l'origine comme un CDN d'origine personnalisé et qu'il ne prend pas en charge le gzipping, je l'ai jusqu'à présent utilisé pour héberger toutes mes images, qui sont référencées par leur nom de domaine Cloudfront dans mon code de site, et optimisées avec loin -en-têtes futurs.

Les fichiers CSS et javascript, en revanche, sont hébergés sur mon propre serveur, car jusqu'à présent, j'avais l'impression qu'ils ne pouvaient pas être servis au format gzip depuis Cloudfront, et que le gain du gzipping (environ 75%) l'emporte sur celui d'utiliser un CDN (environ 50%): Amazon S3 (et donc Cloudfront) ne prend pas en charge la diffusion de contenu gzippé de manière standard en utilisant l'en-tête HTTP Accept-Encoding envoyé par les navigateurs pour indiquer leur prise en charge de la compression gzip, et ils n'ont donc pas pu Gzip et servir des composants à la volée.

Ainsi j'avais l'impression, jusqu'à présent, qu'il fallait choisir entre deux alternatives:

  1. déplacer tous les actifs vers Amazon CloudFront et oublier GZipping;

  2. garder les composants auto-hébergés et configurer notre serveur pour détecter les demandes entrantes et effectuer le GZipping à la volée selon les besoins, ce que j'ai choisi de faire jusqu'à présent.

Il y avait des solutions de contournement pour résoudre ce problème, mais essentiellement cela n'a pas fonctionné . [ lien ].

Il semble maintenant qu'Amazon Cloudfront prend en charge l'origine personnalisée et qu'il est désormais possible d'utiliser la méthode HTTP Accept-Encoding standard pour servir du contenu compressé si vous utilisez une origine personnalisée [ lien ].

Jusqu'à présent, je n'ai pas pu implémenter la nouvelle fonctionnalité sur mon serveur. Le billet de blog que j'ai lié ci-dessus, qui est le seul que j'ai trouvé détaillant le changement, semble impliquer que vous ne pouvez activer le gzipping (barres de contournement, que je ne veux pas utiliser), si vous optez pour une origine personnalisée, qui Je préfère ne pas: je trouve plus simple d'héberger les fichiers correspondants sur mon serveur Cloudfront et de les lier à partir de là. Malgré la lecture attentive de la documentation, je ne sais pas:

  • si la nouvelle fonctionnalité signifie que les fichiers doivent être hébergés sur mon propre serveur de domaine via une origine personnalisée, et si oui, quelle configuration de code y parviendra;

  • comment configurer les en-têtes css et javascript pour vous assurer qu'ils sont servis au format gzip depuis Cloudfront.

Donald Jenkins
la source

Réponses:

202

MISE À JOUR: Amazon prend désormais en charge la compression gzip, donc ce n'est plus nécessaire. Annonce Amazon

Réponse originale:

La réponse est de compresser les fichiers CSS et JavaScript. Oui, tu l'as bien lu.

gzip -9 production.min.css

Cela produira production.min.css.gz. Supprimez le .gz, téléchargez vers S3 (ou quel que soit le serveur d'origine que vous utilisez) et définissez explicitement l'en- Content-Encodingtête du fichier gzip.

Ce n'est pas du gzipping à la volée, mais vous pouvez très facilement l'intégrer dans vos scripts de construction / déploiement. Les avantages sont:

  1. Il ne nécessite aucun processeur pour qu'Apache puisse compresser le contenu lorsque le fichier est demandé.
  2. Les fichiers sont compressés au plus haut niveau de compression (en supposant gzip -9 ).
  3. Vous diffusez le fichier à partir d'un CDN.

En supposant que vos fichiers CSS / JavaScript sont (a) minifiés et (b) suffisamment volumineux pour justifier le processeur requis pour décompresser sur la machine de l'utilisateur, vous pouvez obtenir des gains de performances significatifs ici.

N'oubliez pas: si vous apportez une modification à un fichier mis en cache dans CloudFront, assurez-vous d'invalider le cache après avoir effectué ce type de modification.

Skyler Johnson
la source
37
Après avoir lu votre lien, je dois dire que l'auteur du blog n'est pas informé. "Cependant, si l'utilisateur possède un navigateur qui ne prend pas en charge le codage gzip, les feuilles de style et les javascripts zippés de votre site ne fonctionneront tout simplement pas pour cet utilisateur." Ce navigateur serait probablement trop ancien pour exécuter vos feuilles de style et vos fichiers de script de toute façon. Ces utilisateurs représentent une fraction d'un pour cent.
Skyler Johnson
3
MISE À JOUR: je l'ai résolu. La raison pour laquelle il ne s'affichait pas était que j'avais oublié de définir Content-Type sur text / css. Si vous faites cela, tout va bien, bien que pour une raison quelconque, il semble que vous ne puissiez pas ajouter un en-tête "Accept-Encoding: Vary" dans S3 (ce qui aiderait à évaluer la vitesse de Google) pour les raisons décrites ici: [link ]. De plus, j'ai défini Cache-control pour mettre en cache l'actif, mais il ne semble pas le mettre en cache ...
Donald Jenkins
32
Je viens de le trouver via Google, et je suis désolé de devoir dire que ce n'est pas un bon conseil. Alors que <1% des navigateurs de bureau ne peuvent pas gérer le contenu compressé, de nombreux navigateurs mobiles ne le peuvent pas. Le nombre dépend du public cible que vous regardez; mais la plupart des Nokia S40 plus anciens ont par exemple une compression gzip buggée. La bonne façon est une «origine personnalisée», qui pointe vers un serveur Web Apache / IIS qui effectue la compression de contenu et sert les en-têtes HTTP appropriés. Voici un article de blog qui en décrit l'essentiel: nomitor.com/blog/2010/11/10/…
Jesper M
14
Comment est la situation aujourd'hui, début 2015? Les liens publiés par @JesperMortensen et Simon Peck sont-ils toujours pertinents?
ItalyPaleAle
5
Amazon a annoncé la prise en charge de la compression gzip en décembre 2015, donc cela n'est plus pertinent, il suffit de télécharger le fichier de base et cela fonctionnera. aws.amazon.com/blogs/aws/…
Sean
15

Ma réponse est un décollage à ce sujet: http://blog.kenweiner.com/2009/08/serving-gzipped-javascript-files-from.html

En vous basant sur la réponse de skyler, vous pouvez télécharger une version gzip et non gzip des css et js. Soyez prudent en nommant et en testant dans Safari. Parce que safari ne gérera .css.gzni .js.gzfichiers.

site.jset site.js.jgzet site.csset site.gz.css (vous devrez définir l'en- content-encodingtête sur le type MIME correct pour que ceux-ci fonctionnent correctement)

Ensuite, dans votre page, mettez.

<script type="text/javascript">var sr_gzipEnabled = false;</script> 
<script type="text/javascript" src="http://d2ft4b0ve1aur1.cloudfront.net/js-050/sr.gzipcheck.js.jgz"></script> 

<noscript> 
  <link type="text/css" rel="stylesheet" href="http://d2ft4b0ve1aur1.cloudfront.net/css-050/sr-br-min.css">
</noscript> 
<script type="text/javascript"> 
(function () {
    var sr_css_file = 'http://d2ft4b0ve1aur1.cloudfront.net/css-050/sr-br-min.css';
    if (sr_gzipEnabled) {
      sr_css_file = 'http://d2ft4b0ve1aur1.cloudfront.net/css-050/sr-br-min.css.gz';
    }

    var head = document.getElementsByTagName("head")[0];
    if (head) {
        var scriptStyles = document.createElement("link");
        scriptStyles.rel = "stylesheet";
        scriptStyles.type = "text/css";
        scriptStyles.href = sr_css_file;
        head.appendChild(scriptStyles);
        //alert('adding css to header:'+sr_css_file);
     }
}());
</script> 

gzipcheck.js.jgz est juste sr_gzipEnabled = true; Ceci teste pour s'assurer que le navigateur peut gérer le code gzippé et fournir une sauvegarde s'il ne le peut pas.

Ensuite, faites quelque chose de similaire dans le pied de page en supposant que tous vos js sont dans un seul fichier et peuvent aller dans le pied de page.

<div id="sr_js"></div> 
<script type="text/javascript"> 
(function () {
    var sr_js_file = 'http://d2ft4b0ve1aur1.cloudfront.net/js-050/sr-br-min.js';
    if (sr_gzipEnabled) {
       sr_js_file = 'http://d2ft4b0ve1aur1.cloudfront.net/js-050/sr-br-min.js.jgz';
    }
    var sr_script_tag = document.getElementById("sr_js");         
    if (sr_script_tag) {
    var scriptStyles = document.createElement("script");
    scriptStyles.type = "text/javascript";
    scriptStyles.src = sr_js_file;
    sr_script_tag.appendChild(scriptStyles);
    //alert('adding js to footer:'+sr_js_file);
    }
}());
</script> 

MISE À JOUR: Amazon prend désormais en charge la compression gzip. Annonce, donc ce n'est plus nécessaire. Annonce Amazon

Sean
la source
merci beaucoup pour cette suggestion. Si je vous comprends bien, vous abordez le cas où le navigateur de l'utilisateur n'est pas en mesure de lire le fichier compressé, ce qui peut toujours se produire bien qu'il concerne un pourcentage assez faible de navigateurs de nos jours. Un inconvénient possible de cette solution, si vous vous référez au lien que j'ai publié dans ma question [lien ], c'est que cela signifie que vous ne pouvez pas mettre en cache votre page, car cela ne fonctionnera que si votre code est exécuté dynamiquement à chaque fois qu'un utilisateur se charge la page (qui est bien sûr la mienne).
Donald Jenkins
@DonaldJenkins Je pense que les js seront toujours mis en cache. Lorsque vous créez la balise de script dans le snip js, le js doit toujours être appelé et je pense que s'il est en cache, le navigateur l'utilisera à partir de là.
Sean
2
La page de test blog.kosny.com/testpages/safari-gz indique que l'avertissement "Soyez prudent pour nommer et tester dans Safari. Parce que safari ne gérera pas css.gz ou js.gz" est obsolète. Dans Safari 7 sur Mavericks et dans Safari sur iOS 7, css.gz et js.gz fonctionnent tous les deux. Je ne sais pas quand ce changement s'est produit, je teste uniquement avec les appareils que j'ai.
garyrob
14

Cloudfront prend en charge le gzipping.

Cloudfront se connecte à votre serveur via HTTP 1.0. Par défaut, certains serveurs Web, y compris nginx, ne servent pas de contenu compressé aux connexions HTTP 1.0, mais vous pouvez le dire en ajoutant:

gzip_http_version 1.0

à votre configuration nginx. La configuration équivalente peut être définie pour le serveur Web que vous utilisez.

Cela a pour effet secondaire de faire en sorte que les connexions persistantes ne fonctionnent pas pour les connexions HTTP 1.0, mais comme les avantages de la compression sont énormes, cela vaut vraiment le coup.

Tiré de http://www.cdnplanet.com/blog/gzip-nginx-cloudfront/

Éditer

Servir du contenu compressé à la volée à travers le cloud d'Amazon est dangereux et ne devrait probablement pas être fait. Fondamentalement, si votre serveur Web est en train de compresser le contenu, il ne définira pas de longueur de contenu et enverra plutôt les données en bloc.

Si la connexion entre Cloudfront et votre serveur est interrompue et rompue prématurément, Cloudfront met toujours en cache le résultat partiel et le sert de version mise en cache jusqu'à son expiration.

La réponse acceptée de le compresser d'abord sur le disque puis de servir la version compressée est une meilleure idée car Nginx sera en mesure de définir l'en-tête Content-Length, et donc Cloudfront rejettera les versions tronquées.

Danack
la source
5
-1, Cette réponse n'a rien à voir avec la question. Nginx! = S3 et Cloudfront
Jonathan
@Danack, avez-vous rencontré de nombreux problèmes avec la mise en cache Cloudfront des fichiers semi-récupérés à cause de ce problème? J'essaie de comprendre à quel point c'était un problème pour vous dans la pratique.
Poshest
1
@poshest C'est arrivé. Il y avait très peu d'avantages à servir gzip à la volée (car gzip est si rapide sur le serveur de toute façon), donc je l'ai désactivé dès que je l'ai vu se produire. Les données corrompues sont un problème beaucoup plus important que d'avoir un «temps de premier octet» lent de 200 ms dans les rares cas où le contenu n'existe pas déjà au format gzippé.
Danack
Si un actif ne contient pas de propriété Content-Length dans l'en-tête mais inclut le codage de transfert: fragmenté (comme c'est souvent le cas avec les actifs compressés), CloudFront ne mettra pas en cache un actif partiel s'il ne reçoit pas de segment de terminaison. S'il manque ces deux propriétés, il est possible qu'un actif incomplet soit mis en cache. Voir: docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/…
Cody Duval
5

Nous avons récemment effectué quelques optimisations pour uSwitch.com afin de compresser certains des actifs statiques de notre site. Bien que nous ayons configuré un proxy nginx complet pour ce faire, j'ai également mis en place une petite application Heroku qui fait office de proxy entre CloudFront et S3 pour compresser le contenu: http://dfl8.co

Étant donné que les objets S3 accessibles au public sont accessibles à l'aide d'une structure d'URL simple, http://dfl8.co utilise simplement la même structure. C'est-à-dire que les URL suivantes sont équivalentes:

http://pingles-example.s3.amazonaws.com/sample.css
http://pingles-example.dfl8.co/sample.css
http://d1a4f3qx63eykc.cloudfront.net/sample.css
pingles
la source
5

Hier, Amazon a annoncé une nouvelle fonctionnalité, vous pouvez maintenant activer gzip sur votre distribution.

Cela fonctionne avec s3 sans ajouter de fichiers .gz vous-même, j'ai essayé la nouvelle fonctionnalité aujourd'hui et cela fonctionne très bien. (vous devez cependant invalider vos objets actuels)

Plus d'informations

Chris
la source
0

Vous pouvez configurer CloudFront pour compresser automatiquement les fichiers de certains types et servir les fichiers compressés.

Voir le Guide du développeur AWS

Rafi
la source
Pouvez-vous ajouter plus d'informations sur votre solution (peut-être un exemple) pour en faire une meilleure réponse.
Yagami Light