Escrito por Ramón Saquete
Índice
La compresión gzip debería ser un requisito básico para cualquier hosting que quiera ofrecer un buen servicio. Sin embargo, son muchos los que no activan o configuran correctamente sus servidores para ofrecer el mejor rendimiento. Es bastante común, encontrarnos en la situación de que nosotros debamos configurarlo, a nivel de dominio, via .htaccess, Web.Config o similar.
La técnica consiste simplemente en comprimir la información en el servidor antes de enviarla al navegador cliente que la solicitó, ahorrando tiempo en la transmisión de los datos por la red. Para comprimir la información se puede usar el formato gzip o, alternativamente, deflate.
Gzip es un formato de compresión abierto desarrollado por el proyecto GNU. Como la mayoría de algoritmos de compresión sin pérdida de información, reduce el tamaño de los archivos, sustituyendo las cadenas más frecuentes por cadenas más cortas. En concreto, los formatos gzip y deflate, se basan en el algoritmo LZ77 creado en 1977 por Abraham Lempel y Jacob Ziv, que crea un diccionario con las cadenas que más de repiten y que se sustituyen en el archivo por códigos Huffman, estos códigos son secuencias binarias unívocamente decodificables (se pueden leer sin poner separadores) y son más cortas para las cadenas más frecuentes.
¿Por qué es tan importante?
Esta técnica de WPO es una de las más fáciles de aplicar, puesto que no requiere modificar código, mientras que por otro lado obtiene una mejora notable de rendimiento, debido a que reduce considerablemente la cantidad de información que se debe descargar cada cliente para ver la página.
Su uso es especialmente importante si hemos empotrado imágenes en hojas de estilo o en el código HTML mediante Data URIs, ya que al convertir las imágenes a texto su tamaño aumenta y, con la compresión gzip, se vuelven a quedar como estaban.
¿Cómo funciona?
Para que se pueda utilizar, tanto el cliente como el servidor deben ser compatibles con la compresión gzip. Los navegadores que lo son (todos los que no tengan más de 10 años), envían en la cabecera de sus peticiones del protocolo HTTP/1.1 el siguiente parámetro:
GET / Host: www.humanlevel.com Accept-Encoding: gzip, deflate
Con esta cabecera, el cliente está diciéndole al servidor: dame la página home de www.humanlevel.com, puedes enviarmela comprimida usando el algoritmo gzip o deflate.
El servidor al ver esta petición puede responderle con el contenido comprimido o no. Si se lo devuelve comprimido incluirá el siguiente parámetro en la cabecera de respuesta:
Content-Encoding:gzip
Con este parámetro, el servidor le está diciendo al cliente: te envío la página comprimida con gzip. De esta manera el cliente sabe que tiene que aplicar dicho algoritmo para descomprimirla. Cuando la cabecera no aparece, significa que el contenido va sin comprimir.
Normalmente, el contenido comprimido siempre viene en gzip. El otro algoritmo de compresión alternativo es deflate, pero nunca se usa, puesto que comprime menos y los navegadores que descomprimen deflate también descomprimen gzip, pero al revés no, puesto que gzip está basado en deflate.
Google Chrome envía en el Accept-Encoding un formato de compresión propietario de Google, el SDCH (Shared Dictionary Compression over HTTP), pero todavía no hay servidores Web que compriman en este formato, ni parece haber interés en que lo vaya a haber, puesto que ya se propuso hace varios años.
El servidor, adicionalmente, debería incluir, el siguiente parámetro junto al anterior:
Vary:Accept-Encoding
Este parámetro va dirigido a servidores proxy intermedios y sirve para solucionar la siguiente situación: supongamos que un navegador que no puede usar gzip hace la primera petición y la página se almacena sin comprimir en la caché del proxy, las siguientes respuestas irán todas sin comprimir aunque los navegadores la pidan en gzip. Si la primera petición es de un navegador que sí lo puede usar, las siguientes respuestas irán todas comprimidas aunque el navegador no pueda descomprimirlas y mostrarlas al usuario. Con este parámetro le decimos al proxy que deben almacenar en su caché versiones distintas cuando varíe el valor del parámetro Accept-Encoding en la petición del navegador, solucionando el problema.
Aunque usar gzip supone un coste de CPU adicional, en el servidor para comprimir y en el cliente para descomprimir, la ganancia de rendimiento que conseguimos transmitiendo la información más rápido por la red, es mucho mayor, no sólo porque ocupe menos, si no porque obtendremos menos paquetes de datos en los que se partirá la información, a la hora de enviarla y volverla a juntar en el destino.
¿Qué debemos tener en cuenta en la configuración?
En primer lugar hemos que tener claro que es lo que se debe comprimir y lo que no, puesto que al comprimir determinados archivos perderemos rendimiento.
Debemos aplicar la compresión a aquellos archivos que no estén ya comprimidos. Me estoy refiriendo principalmente a los archivos de texto HTML, JavaScript, CSS, XML y JSON, y estén generados de forma estática o dinámica. Haciendo esto, de media, conseguiremos ahorrar entre un 60% y un 70% del tamaño que ocupan estos archivos.
Si intentamos comprimir archivos que ya vienen comprimidos, incrementaremos ligeramente el tamaño de estos archivos. En este caso, me estoy refiriendo sobre todo a imágenes JPG, GIF o PNG y archivos PDF. Esto unido al sobre coste de CPU que tiene que realizar el servidor al comprimirlos y el cliente al descomprimirlos, conseguirá que el tiempo de carga aumente, en lugar de disminuir. Esto es debido a que llegado un punto, la información no se puede comprimir más, de forma que al intentar comprimirla de nuevo, hacemos el archivo más grande al incluirle una cabecera nueva necesaria para su descompresión.
También hay que tener en consideración el tamaño del archivo. No merece la pena comprimir un archivo de menos de 1 KiB, puesto que es bastante probable que al enviarse por la red, nunca se llegue a segmentar la información, tardando lo mismo en transmitirse, tanto si va comprimido como si no, con el sobrecoste de CPU debido a trabajar con información comprimida en el cliente y en el servidor. No es fácil establecer cuál debe ser el tamaño mínimo de archivo necesario para realizar la compresión, puesto que depende de múltiples factores de las redes que atraviese hasta llegar a su destino, pero en general, suele ser peor para el rendimiento comprimir archivos menores de 1 o 2 KiB.
En ocasiones, se permite configurar el servidor para que guarde una caché de los archivos comprimidos, para no tenerlos que volver a comprimir en cada nueva petición. Cuando su correspondiente archivo sin comprimir cambie, se actualizará el archivo original.
Otra opción interesante con la que nos podemos encontrar, es la de regular el nivel compresión, de forma que aumentando el coste de CPU para comprimir los archivos, podemos hacer que ocupen menos, o al contrario, disminuir el coste de CPU a costa de que ocupen más los archivos. El ajuste de esta opción dependerá del uso de CPU del servidor en cada caso.
¿Cómo se configura?
Vamos a ver los parámetros más importantes de los servidores Web más habituales:
Apache 2.x
En Apache 2.x debemos activar el módulo mod_deflate (aunque se llama deflate utiliza Gzip) y establecer la configuración de la siguiente forma:
Parámetro | Acción |
SetOutputFilter DEFLATE | Habilitar la compresión |
AddOutputFilterByType DEFLATE text/html text/css application/x-javascript | Establecer los tipos MIME de los archivos a comprimir |
DeflateCompressionLevel 5 | Establecer el nivel de compresión (entre 0 y 9) |
Establecer los archivos a comprimir con el tipo MIME, siempre será mejor que especificar la extensión de los archivos, ya que aplicará la compresión aunque el archivo sea generado dinámicamente.
Apache 1.3
En la versiones anteriores de Apache, de la 1.3 hacia atrás, debemos activar el módulo mod_gzip y establecer la configuración de la siguiente forma en el archivo httpd.conf (si es a nivel de servidor) o en el .htaccess (si es a nivel de directorio):
Parámetro | Acción |
mod_gzip_on Yes | Activar el módulo |
mod_gzip_item_include file \.js$ | Activar la compresión para los archivos con extensión .js |
mod_gzip_item_include mime ^text/html$ | Activar la compresión para los archivos con el tipo MIME HTML |
mod_gzip_minimum_file_size | Establece el tamaño minimo necesario para que se comprima el archivo |
mod_gzip_can_negotiate Yes | Establece que se puedan servir archivos comprimidos |
gzip_update_static Yes | Los archivos en gzip cacheados se actualizan automáticamente y no de forma manual |
PHP
Desde PHP también puede habilitar la compresión con el siguiente opción del archivo php.ini:
zlib.output_compression = On
Si tenemos la compresión ya habilitada con un módulo de Apache (opción que es preferible), no debemos hacer esto porque la configuración entraría en conflicto.
Internet Information Serve r7
En IIS7 tenemos la siguiente pantalla de configuración que parece al pinchar en compression dentro de las opciones generales:
Después dentro del archivo Web.Config debemos establecer los siguientes valores:
<system.webServer>
<urlCompression doStaticCompression=»true» doDynamicCompression=»true» dynamicCompressionBeforeCache=»true»/>
<httpCompression directory=»%SystemDrive%\inetpub\
temp\IIS Temporary Compressed Files»>
<scheme name=»gzip» dll=»%Windir%\system32\inetsrv\gzip.dll»/>
<dynamicTypes>
<add mimeType=»text/*» enabled=»true»/>
<add mimeType=»message/*» enabled=»true»/>
<add mimeType=»application/javascript» enabled=»true»/>
<add mimeType=»*/*» enabled=»false»/>
</dynamicTypes>
<staticTypes>
<add mimeType=»text/*» enabled=»true»/>
<add mimeType=»message/*» enabled=»true»/>
<add mimeType=»application/javascript» enabled=»true»/>
<add mimeType=»*/*» enabled=»false»/>
</staticTypes>
</httpCompression>
<urlCompression doStaticCompression=»true» doDynamicCompression=»true»/>
</system.webServer>
Los parámetros doStaticCompression y doDynamicCompression, se refieren a que debe comprimir tanto archivos estáticos como dinámicos.
Espero que haya quedado clara cuál es la forma correcta de configurar la compresión gzip ¿y vuestra Web?, ¿tiene la compresión gzip configurada correctamente?
Hola ramon gracias por tu articulo , muy comppleto , mi duda es la sigte al comprobar la velocidad de la web a traves de gtmetrix uno de los parametros que me pone a optimizar es la compresion gZip , justamente la habia habilitado anteriormente , no obstante lo hize nuevamente a traves del hosting pero me sigue saliendo el parametro de compresion gzip a habilitar , me salen 3 videos de youtube que tengo en la pagina de inicio incrustados , sabes a que puede deberse ? o si hay alguna forma de eliminar esta cuestion
Hola Luis,
Cuando una web tiene recursos de dominios externos que no dependen de nuestro hosting, las herramientas automáticas de evaluación del WPO no tienen en cuenta esto y nos sacan alertas por cualquier técnica de optimización que no se esté aplicando a esos recursos. Me temo que la única forma de evitarlo es eliminar dichos recursos, lo que no es buena solución.
Saludos
Antes que nada gracias por la información. Mi pregunta es la siguiente. Estoy trabajando con un servidor que no tiene apache y tampoco la configuración de comprimir archivos. Como puedo hacer para comprimir los archivos js y css (Ya quite los saltos de linea y comentarios) y acelerar la velocidad con la que se carga la pagina.
Hola Alejandro,
Para poderte contestar mejor tendría que saber que servidor web utilizas. Quizás exista un módulo que puedas instalar para el servidor web que utilizas. Si no, tendrás que optar por una solución como la del primer comentario de esta entrada, que consistiría en subir tu mismo los archivos comprimidos y hacer que el servidor devuelva las cabeceras correctas para ese tipo de archivos.
Saludos
¡Muchas gracias por tu respuesta! Estaba perdido en este tema y me has ayudado bastante. Uno de los mejores artículos que he leído por lo mucho que aporta y lo rápido que se puede hacer.
Saludos
Muy buen artículo, completísimo y con ejemplos prácticos muy claros, incluyendo el del comentario. Un gran trabajo.
Aprovechando tus buenos conocimientos, te voy a plantear una duda:
En mi web tengo el index en HTML hecho a mano, y en la carpeta /blog tengo un WordPress. Si en el .htaccess de la carpeta raíz tengo activada la compresión gzip, ¿daría problemas si el WordPress también tiene la compresión activada? ¿o no debería generar problemas esa coincidencia?
Saludos
Gracias, me alegro que te guste. Vamos a completarlo un poco más.
Cuando se activa la compresión desde WordPress, normalmente se hace la compresión desde PHP de esta forma:
if(!ob_start(«ob_gzhandler»)) ob_start();
Es una función que captura todo lo que va a devolver y lo comprime. Si también está habilitada la compresión a través de mod_gzip o mod_deflate o con la extensión de PHP zlib (más lento), puedes estar comprimiendo los archivos dos veces.
Es mejor usar los módulos de servidor antes que la soluciones que se aplican directamente sobre el código (ob_gzhandler y la extensión zlib), además de que estas soluciones sólo sirven para código PHP y no para el resto de archivos.
Saludos
Hola Sergio,
Sí ya has probado los parámetros que he comentado en la entrada para los módulos mod_deflate y mod_gzip, y no te ha funcionado, entonces puede que no tengas ninguno de los dos módulos activados. En estos casos la única solución es subir «a mano» los archivos comprimidos al servidor, puedes establecer la siguiente correspondencia:
Para el archivo style.css => style.css.gz, para el archivo script.js => script.js.gz y así con todos los .css y .js. Después tendrás que añadir al .htaccess lo siguiente:
<IfModule mod_headers.c>
# Servir archivos CSS comprimidos si exiten y el cliente acepta gzip
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.css $1\.css\.gz [QSA]
# Servir archivos JS comprimidos si exiten y el cliente acepta gzip
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.js $1\.js\.gz [QSA]
# Establece el content type correcto, y prevenir que mod_deflate recomprima el gzip de nuevo si esta activo
RewriteRule \.css\.gz$ – [T=text/css,E=no-gzip:1]
RewriteRule \.js\.gz$ – [T=text/javascript,E=no-gzip:1]
<FilesMatch «(\.js\.gz|\.css\.gz)$»>
# Establece el tipo correcto de codificación
Header set Content-Encoding gzip
# Fuerza a los proxies a cachear los archivos comprimidos y sin comprimir por separado
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
De esta forma el servidor no gasta nunca CPU en comprimir, aunque es mucho más engorroso actualizar, pero si el hosting no te permite tener acceso para activar módulos de Apache, lo cual es lo más habitual en un hosting compartido, no puedes hacer otra cosa.
Espero que te sirva.
Saludos
Y a nivel de .htacces: ¿cómo debemos activar el nivel de compresión y seleccionar los MIME? Me he encontrado con hostings que no lo activan por defecto.
Un saludo.