Sirviendo CSS y JavaScript comprimidos desde Amazon CloudFront a través de S3

194

He estado buscando formas de hacer que mi sitio se cargue más rápido y una forma en que me gustaría explorar es hacer un mayor uso de Cloudfront.

Debido a que Cloudfront originalmente no fue diseñado como un CDN de origen personalizado y porque no admitía el gzipping, hasta ahora lo he estado usando para alojar todas mis imágenes, a las que hace referencia su nombre de Cloudfront en el código de mi sitio, y optimizado con mucho -futures encabezados.

Los archivos CSS y JavaScript, por otro lado, están alojados en mi propio servidor, porque hasta ahora tenía la impresión de que no podían ser enviados desde Cloudfront, y que la ganancia de gzipping (alrededor del 75 por ciento) supera eso por usar un CDN (aproximadamente el 50 por ciento): Amazon S3 (y, por lo tanto, Cloudfront) no admitía la publicación de contenido comprimido de manera estándar al usar el encabezado HTTP Accept-Encoding que se envía por los navegadores para indicar su compatibilidad con la compresión gzip, y por lo que no pudieron Gzip y servir componentes sobre la marcha.

Por lo tanto, tenía la impresión, hasta ahora, de que había que elegir entre dos alternativas:

  1. mover todos los activos a Amazon CloudFront y olvidarse de GZipping;

  2. mantenga los componentes autohospedados y configure nuestro servidor para detectar solicitudes entrantes y realizar GZipping sobre la marcha, según corresponda, que es lo que elegí hacer hasta ahora.

No eran soluciones para resolver este problema, pero esencialmente éstos no funcionaron . [ enlace ].

Ahora, parece que Amazon Cloudfront es compatible con el origen personalizado, y que ahora es posible usar el método de codificación de aceptación HTTP estándar para servir contenido comprimido si está utilizando un origen personalizado [ enlace ].

Hasta ahora no he podido implementar la nueva función en mi servidor. La publicación de blog a la que he vinculado anteriormente, que es la única que encontré que detalla el cambio, parece implicar que solo puede habilitar el gzipping (soluciones alternativas de barras, que no quiero usar), si opta por un origen personalizado, que Prefiero no hacerlo: me resulta más sencillo alojar los archivos correspondientes en mi servidor Cloudfront y vincularlos desde allí. A pesar de leer detenidamente la documentación, no sé:

  • si la nueva característica significa que los archivos deben estar alojados en mi propio servidor de dominio a través de un origen personalizado, y si es así, qué configuración de código logrará esto;

  • cómo configurar los encabezados css y javascript para asegurarse de que se sirvan comprimidos desde Cloudfront.

Donald Jenkins
fuente

Respuestas:

202

ACTUALIZACIÓN: Amazon ahora admite la compresión gzip, por lo que ya no es necesario. Anuncio de Amazon

Respuesta original:

La respuesta es descomprimir los archivos CSS y JavaScript. Sí, lo leiste bien.

gzip -9 production.min.css

Esto producirá production.min.css.gz. Elimine .gz, cargue en S3 (o el servidor de origen que esté utilizando) y configure explícitamente el Content-Encodingencabezado para el archivo gzip.

No es un gzipping sobre la marcha, pero podría fácilmente incluirlo en sus scripts de compilación / implementación. Las ventajas son:

  1. No requiere CPU para que Apache comprima el contenido cuando se solicita el archivo.
  2. Los archivos se comprimen en el nivel de compresión más alto (suponiendo gzip -9).
  3. Estás sirviendo el archivo desde un CDN.

Suponiendo que sus archivos CSS / JavaScript están (a) minimizados y (b) lo suficientemente grandes como para justificar la CPU requerida para descomprimir en la máquina del usuario, puede obtener ganancias significativas de rendimiento aquí.

Solo recuerde: si realiza un cambio en un archivo que está en caché en CloudFront, asegúrese de invalidar el caché después de realizar este tipo de cambio.

Skyler Johnson
fuente
37
Después de leer su enlace, debo decir que el autor del blog no está informado. "Sin embargo, si el usuario tiene un navegador que no admite la codificación gzip, las hojas de estilo y javascripts comprimidos de su sitio simplemente no funcionarán para ese usuario". Es probable que este navegador sea demasiado viejo para ejecutar sus hojas de estilo y archivos de script de todos modos. Estos usuarios representan una fracción de un porcentaje.
Skyler Johnson el
3
ACTUALIZACIÓN: Lo resolví. La razón por la que no se mostraba era porque había olvidado configurar Content-Type en text / css. Si hace eso, está bien, aunque por alguna razón parece que no puede agregar un encabezado "Accept-Encoding: Vary" en S3 (que ayudaría con la calificación de Google Speed) por los motivos descritos aquí: [enlace ] Además, me puse Cache-Control para almacenar en caché el activo, pero no parece ser el almacenamiento en caché que ...
Donald Jenkins
32
Acabo de encontrar esto a través de Google, y lamento tener que decir que este no es un buen consejo. Si bien <1% de los navegadores de escritorio no pueden manejar contenido comprimido, muchos navegadores móviles no pueden. La cantidad depende del público objetivo al que esté mirando; pero la mayoría de los Nokia S40 más antiguos tienen compresión gzip con errores, por ejemplo. La forma correcta es un "Origen personalizado", que apunta a un servidor web Apache / IIS que realiza la compresión de contenido y sirve los encabezados HTTP adecuados. Aquí hay una publicación de blog que describe su esencia: nomitor.com/blog/2010/11/10/…
Jesper M
14
¿Cómo está la situación ahora, a principios de 2015? ¿Siguen siendo relevantes los enlaces publicados por @JesperMortensen y Simon Peck?
ItalyPaleAle
55
Amazon anunció el soporte para la compresión gzip en diciembre de 2015, por lo que ahora es irrelevante, solo suba el archivo básico y funcionará. aws.amazon.com/blogs/aws/…
Sean
15

Mi respuesta es un despegue sobre esto: http://blog.kenweiner.com/2009/08/serving-gzipped-javascript-files-from.html

A partir de la respuesta de Skyler, puede cargar una versión gzip y no gzip de css y js. Tenga cuidado al nombrar y probar en Safari. Porque el safari no manejará .css.gzo.js.gz archivará.

site.jsy site.js.jgzy site.cssy site.gz.css (deberá configurar el content-encodingencabezado con el tipo MIME correcto para que estos se publiquen correctamente)

Luego en su página poner.

<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 es solo sr_gzipEnabled = true; esto prueba para asegurarse de que el navegador pueda manejar el código comprimido y proporcionar una copia de seguridad si no pueden.

Luego, haga algo similar en el pie de página, suponiendo que todos sus js estén en un archivo y puedan ir en el pie de página.

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

ACTUALIZACIÓN: Amazon ahora es compatible con la compresión gzip. Anuncio, por lo que ya no es necesario. Anuncio de Amazon

Sean
fuente
Muchas gracias por esa sugerencia. Si lo entiendo correctamente, está abordando el caso en el que el navegador del usuario no puede leer el archivo comprimido, lo que aún puede ocurrir, aunque actualmente se trata de un porcentaje bastante pequeño de navegadores. Un posible inconveniente de esta solución, si hace referencia al enlace que publiqué en mi pregunta [link ] es que no puede almacenar en caché su página, ya que solo funcionará si su código se ejecuta dinámicamente cada vez que un usuario carga la página (que por supuesto es la mía).
Donald Jenkins
@DonaldJenkins Creo que el js seguirá en caché. Cuando construye la etiqueta de secuencia de comandos en el fragmento js, ​​aún debe llamarse a js y creo que si está en caché, el navegador lo usará desde allí.
Sean
2
La página de prueba blog.kosny.com/testpages/safari-gz indica que la advertencia "Tenga cuidado al nombrar y probar en Safari. Porque el safari no manejará css.gz o js.gz" está desactualizada. En Safari 7 en Mavericks y en Safari en iOS 7, funcionan css.gz y js.gz. No sé cuándo ocurrió este cambio, solo estoy probando con los dispositivos que tengo.
garyrob
14

Cloudfront admite gzipping.

Cloudfront se conecta a su servidor a través de HTTP 1.0. De manera predeterminada, algunos servidores web, incluido nginx, no sirven contenido comprimido a las conexiones HTTP 1.0, pero puede indicar que lo haga agregando:

gzip_http_version 1.0

a su configuración nginx. La configuración equivalente podría establecerse para cualquier servidor web que esté utilizando.

Esto tiene un efecto secundario de hacer que las conexiones de mantenimiento no funcionen para las conexiones HTTP 1.0, pero como los beneficios de la compresión son enormes, definitivamente vale la pena.

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

Editar

Servir contenido que se comprime sobre la marcha a través del frente de la nube de Amazon es peligroso y probablemente no debería hacerse. Básicamente, si su servidor web está comprimiendo el contenido, no establecerá una longitud de contenido y, en su lugar, enviará los datos como fragmentados.

Si la conexión entre Cloudfront y su servidor se interrumpe y se corta prematuramente, Cloudfront aún almacena en caché el resultado parcial y lo sirve como la versión en caché hasta que caduque.

La respuesta aceptada de comprimirlo primero en el disco y luego servir la versión comprimida es una mejor idea, ya que Nginx podrá establecer el encabezado Content-Length, por lo que Cloudfront descartará las versiones truncadas.

Danack
fuente
55
-1, esta respuesta no tiene nada que ver con la pregunta. Nginx! = S3 y Cloudfront
Jonathan
@Danack, ¿experimentó muchos problemas con el almacenamiento en caché de Cloudfront a medio recuperar archivos debido a este problema? Estoy tratando de entender cuánto de este problema fue para ti en la práctica.
más elegante
1
@poshest Sucedió. Hubo muy pocos beneficios al servir gzipped sobre la marcha (ya que gzip es tan rápido en el servidor de todos modos), así que lo apagué tan pronto como lo vi. Los datos dañados son un problema mucho más grande que tener un "tiempo para el primer byte" ser 200 ms lento en los casos excepcionales en los que el contenido aún no existe en formato comprimido.
Danack
Si a un activo le falta una propiedad Content-Length en el encabezado pero incluye Transfer-Encoding: fragmentado (como suele ser el caso con los activos comprimidos), CloudFront NO almacenará en caché un activo parcial si no recibe un fragmento final. Si le faltan estas dos propiedades, es posible que se almacene en caché un activo incompleto. Ver: docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/…
Cody Duval
5

Hemos realizado algunas optimizaciones para uSwitch.com recientemente para comprimir algunos de los activos estáticos en nuestro sitio. Aunque configuramos un proxy nginx completo para hacer esto, también he creado una pequeña aplicación de Heroku que sirve de proxy entre CloudFront y S3 para comprimir contenido: http://dfl8.co

Dado que se puede acceder a los objetos S3 de acceso público utilizando una estructura de URL simple, http://dfl8.co solo usa la misma estructura. Es decir, las siguientes URL son equivalentes:

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

Ayer, Amazon anunció una nueva función, ahora puede habilitar gzip en su distribución.

Funciona con s3 sin archivos .gz agregados, probé la nueva característica hoy y funciona muy bien. (aunque necesita invalidar sus objetos actuales)

Más información

Chris
fuente
0

Puede configurar CloudFront para comprimir automáticamente archivos de ciertos tipos y servir los archivos comprimidos.

Consulte la Guía para desarrolladores de AWS

Rafi
fuente
¿Puede agregar más información sobre su solución (tal vez un ejemplo) para que sea una mejor respuesta.
Yagami Light