Compresión web · 12 min read · Sep 15, 2025
mod_gzip - sirviendo contenido comprimido por el servidor web Apache - Página 9
Autor: Michael Schröpl
Compresión a través de negociación
Usar una función de compresión configurable como mod_gzip debe ser siempre algún tipo de negociación de contenido, es decir, servir diferentes contenidos condicionalmente para la misma URL solicitada, dependiendo de información específica dentro de los encabezados HTTP.
Por otro lado, HTTP permite el almacenamiento temporal de respuestas a solicitudes HTTP en cachés, especialmente al usar servidores proxy. Si ahora
- un cliente HTTP envía una solicitud,
- la respuesta correspondiente se sirve en forma comprimida y se almacena por algún proxy y
- posteriormente otro cliente HTTP envía una solicitud para la URL en cuestión,
entonces el servidor proxy - que no posee más información - tiene un problema:
- ¿Está autorizado para servir el contenido en caché a este segundo cliente HTTP también, o
- debe reenviar la solicitud al servidor HTTP?
Porque solo el servidor HTTP puede finalmente averiguar (basándose en su configuración que contiene las reglas de filtro correspondientes) si el segundo cliente HTTP puede recibir también datos de respuesta comprimidos.
Por cierto, esto no es un efecto de usar un procedimiento de compresión solo, sino un problema general sobre el almacenamiento en caché de datos HTTP cuyo contenido no puede especificarse de manera inequívoca por una URL dentro de la caché de un servidor proxy o servidores similares equipados en la ruta de transporte. Esto incluye procedimientos de negociación de cualquier tipo, así como la presentación de información adicional en los encabezados HTTP, como datos de autenticación o cookies.
Requisitos de rendimiento
Por supuesto, uno puede intentar evitar el problema negando explícitamente almacenar los datos de la respuesta correspondiente (usando los encabezados HTTP correspondientes Expires: y Pragma: en HTTP/1.0 y Cache-Control: en HTTP/1.1) a todos los servidores proxy existentes en el camino entre el cliente y el servidor.
Pero el objetivo de la compresión es acelerar la transferencia de datos (reduciendo el volumen de datos) - y almacenar datos sirve al mismo objetivo (reduciendo accesos al servidor HTTP). Y una optimización de rendimiento no debería llevar a que otra ya no sea utilizable, especialmente ya que estas dos no se reemplazan entre sí, sino que pueden complementarse efectivamente en el caso en cuestión.
Información sobre parámetros de negociación
La especificación HTTP contiene la definición del Vary encabezado HTTP donde el servidor HTTP puede informar al servidor proxy sobre
- si la respuesta fue el resultado único de una solicitud de URL o
- si otros atributos de una solicitud para la misma URL podrían llevar a resultados diferentes.
Su valor puede contener una lista de nombres de otros encabezados HTTP cuyo contenido ha sido relevante para servir esta respuesta muy específica para una solicitud. Así, el servidor HTTP puede incluso informar al servidor proxy sobre cuáles encabezados HTTP han influido en la decisión sobre el contenido servido.
Cuando un servidor proxy reenvía una solicitud a un servidor HTTP y quiere almacenar la respuesta dentro de su caché más tarde, entonces aún debería estar en posesión de los encabezados HTTP de la solicitud original cuando llega la respuesta del servidor HTTP.
Ahora, si el servidor HTTP marca un contenido condicional de una respuesta mediante el correspondiente encabezado Vary, entonces
- el servidor proxy debe almacenar en su caché no solo el contenido de esta respuesta, sino toda la información relevante de los encabezados HTTP (cuyos nombres fueron enumerados en la lista de valores del encabezado Vary de la respuesta) de la solicitud también, y
- no debe servir este contenido en caché como respuesta a solicitudes posteriores a menos que la información de los encabezados HTTP correspondientes de tal solicitud subsiguiente al menos ‘coincida’ con los de la solicitud original, es decir, sea semánticamente idéntica a los valores de la solicitud original para cada uno de estos encabezados.
Restricciones resultantes para el servidor HTTP
Las explicaciones anteriores han mostrado cómo un servidor proxy puede manejar correctamente la entrega condicional de respuestas HTTP (siendo el resultado de una Negociación de Contenido) y con la máxima utilización de su efecto de almacenamiento en caché al mismo tiempo - suponiendo que
- el servidor HTTP proporciona al servidor proxy suficiente información sobre los parámetros de negociación y
- el servidor proxy está en posesión de la información correspondiente en caso de una solicitud subsiguiente a la misma URL por otro cliente HTTP.
Pero esto último significa ahora una restricción para los grados de libertad del proceso de negociación. Porque si el servidor proxy debe decidir sobre si puede servir su contenido en caché o no exclusivamente basándose en información dentro de una solicitud HTTP, entonces las reglas de negociación de los servidores HTTP no deben referirse a nada más que al contenido de los encabezados HTTP.
Pero desafortunadamente esta precondición no es cumplida por mod_gzip, ya que de las seis clases de reglas de filtro proporcionadas
- dos ‘legales’ (reqheader y uri) se refieren exclusivamente al contenido de los encabezados HTTP, pero
- cuatro otras ‘ilegales’ (rspheader, handler, file y mime) se refieren a información que estará disponible solo durante la evaluación de la solicitud por el servidor HTTP.
Así que si un servidor mejorado con mod_gzip usa una de estas reglas de filtro ‘ilegales’, entonces el servidor proxy no podrá decidir correctamente sobre la aplicabilidad de su contenido en caché para responder a solicitudes posteriores.
Al hacerlo, tampoco ayuda mucho al servidor proxy si mod_gzip notificara al servidor proxy sobre estar evidentemente sobrecargado (proporcionando una lista completa de las clases de reglas de filtro significativas para esta solicitud dentro de algún encabezado Vary: si eso fuera incluso legal). Todo lo que el servidor proxy podría hacer es usar la ocurrencia de una de estas cuatro clases de reglas de filtro ‘ilegales’ como criterio para no almacenar el contenido de la respuesta.
Esto por sí solo no sería tan malo - mientras el servidor HTTP se limite a usar nada más que reglas ‘legales’, podría cooperar óptimamente con un servidor proxy.
Pero desafortunadamente hacerlo es imposible con mod_gzip 1.3.19.1a.
La integración de mod_gzip 1.3.19.1a en la arquitectura de Apache 1.3 se realiza de una manera relativamente compleja:
- En la fase de procesamiento 1, mod_gzip verifica si debería estar interesado en manejar los resultados de esta solicitud y prepararse para ello - basándose en las reglas de cuatro clases (reqheader, uri, file y handler, es decir, dos clases de reglas ‘legales’ y dos ‘ilegales’)
- En la fase de procesamiento 2, mod_gzip verifica si ahora debería comprimir el contenido de respuesta (ahora disponible) - basándose en las reglas de dos clases (rspheader y mime, ambas clases de reglas ‘ilegales’).
Para la autorización exitosa de una solicitud de compresión, al menos se requiere el cumplimiento de una regla include de cualquiera de ambas fases (y el incumplimiento de todas las reglas exclude).
Pero como ambas clases de reglas include de la fase 2 son ‘ilegales’, cada lista de clases de reglas de filtro relevantes para una compresión exitosa en la implementación actual de mod_gzip debe al menos cubrir una clase de regla ‘ilegal’.
Por lo tanto, es imposible proporcionar a un servidor proxy información que pueda usar para decidir sobre la aplicabilidad de algún contenido en caché - la información presentada siempre excederá la comprensión del servidor proxy.
Encabezados Vary en mod_gzip 1.3.19.2a y posteriores
A partir de la versión 1.3.19.2a, mod_gzip está enviando encabezados Vary: - para cada una de las solicitudes donde el módulo ha estado involucrado al menos una vez (independientemente de si se han servido datos comprimidos o no).
En este estado de investigación para mod_gzip, cada solicitud (independientemente de si la respuesta se ha servido realmente en forma comprimida o no) es potencialmente una negociación:
- al menos sobre el encabezado Accept-Encoding HTTP, y
- posiblemente sobre otros encabezados HTTP también (es decir, todos aquellos que ocurren dentro de las reglas de filtro de la clase reqheader)
Hasta ahora, mod_gzip no es aún capaz de generar el mejor conjunto posible, es decir, el conjunto mínimo de encabezados Vary: requeridos - para esto sería necesario reescribir completamente el procedimiento de evaluación de reglas de mod_gzip.
Como primer paso, el módulo desde la versión 1.3.19.2a envía un encabezado Vary: que contiene
- el valor Accept-Encoding así como
- los nombres de cada encabezado que se utiliza dentro de cualquier regla reqheader,
porque cada una de estas reglas podría marcar la diferencia para el resultado de la negociación, y en cada uno de estos casos el resultado dependería de los valores de los encabezados HTTP recibidos. En ciertos casos, esto puede ser demasiado (y luego obstaculizar masivamente el almacenamiento eficiente de contenido), pero al menos es algo con lo que comenzar.
Como mejora a esta estrategia, mod_gzip 1.3.26.1a no está enviando ningún encabezado Vary: si la compresión de la solicitud en cuestión ha sido rechazada debido a una regla mod_gzip_item_exclude de tipo
file,
uri o
handler
ya que la evaluación de esta regla no puede haber dependido de los encabezados HTTP recibidos, y por lo tanto en estos casos en realidad no ha tenido lugar ninguna negociación (sobre dimensiones que podrían contener diferentes valores para diferentes solicitudes HTTP).
Si deseas que no se envíen encabezados Vary: para archivos que estás seguro de que nunca se servirán en forma comprimida debido a otras reglas de configuración, tendrías que desactivar mod_gzip para estos.
Un ejemplo para no enviar encabezados Vary: para imágenes GIF que podrían ser almacenadas en caché por algún proxy como Squid 2.4 podría verse así:
mod_gzip_on No
Para las versiones futuras, las siguientes tareas permanecen abiertas:
- Reconocer en todos los casos posibles que la reacción a la solicitud actual nunca puede causar que se sirvan datos comprimidos porque alguna regla mod_gzip_item_exclude independiente de los atributos de la solicitud está activada.
- Reconocer que ha tenido lugar alguna negociación que no puede ser descrita por una lista de nombres de encabezados HTTP - en este caso Vary: * debería ser enviado (y la documentación para mod_gzip debería señalar explícitamente que estas directivas se utilicen solo si es absolutamente necesario, ya que su uso tendrá un efecto negativo en el trabajo de los proxies de almacenamiento en caché).
- Verificar si son posibles constelaciones donde solo se requiere un subconjunto de nombres de encabezados de todas las reglas reqheader en un encabezado Vary: - cuantos menos nombres haya, menos variantes tendrán que ser almacenadas en la caché del proxy en paralelo.
Negociación sobre otras dimensiones que no sean encabezados HTTP
En casos muy especiales, es decir, al usar ciertas directivas de configuración, se realiza alguna negociación por parte de mod_gzip sobre dimensiones que ni siquiera pueden expresarse en términos de nombres de encabezados HTTP. Esto se aplica a las directivas
- mod_gzip_min_http (versión mínima de HTTP requerida) así como
- mod_gzip_handle_methods (métodos HTTP a manejar)
En ambos casos, mod_gzip no puede explicar a un proxy lo que se ha hecho al decir los nombres de los encabezados HTTP. La reacción apropiada de acuerdo con la especificación HTTP/1.1 es enviar el encabezado Vary: *.
mod_gzip 1.3.26.1a está enviando un encabezado Vary: ** si se ha utilizado la directiva mod_gzip_min_http*.
En cuanto a la directiva mod_gzip_handle_methods, actualmente parece no estar aún absolutamente claro si dos solicitudes HTTP para la misma URI pero usando diferentes métodos HTTP realmente piden la misma entidad HTTP - esto decidirá si un encabezado Vary: * tendrá que ser enviado al usar esta directiva también, y será un tema a resolver en lanzamientos futuros.
Pero como en este caso un servidor proxy no puede entender el tipo de negociación realizada, no está autorizado a almacenar respuestas que lleven esta marca dentro de alguna caché.
Por lo tanto, usar una de estas directivas desactiva completamente el almacenamiento en caché de cada una de las respuestas enviadas por este servidor HTTP, ya sea en forma comprimida o no comprimida. Por lo tanto, te aconsejamos que no uses ninguna de estas directivas más.
El UserAgent como caso especial
Almacenar variantes de diferentes parámetros de negociación en paralelo en una caché proxy puede ser razonable si solo pueden ocurrir unos pocos valores posibles - como en el caso de Content-Encoding. Si hay un gran número de valores posibles, entonces el almacenamiento paralelo de variantes ya no es factible.
Exactamente esto se aplica al nombre del UserAgent como identificación del cliente HTTP. Cada subversión de un navegador envía una cadena de UserAgent compleja que contiene no solo el nombre y la versión de los navegadores, sino también información adicional (idioma nacional, nombre y versión del sistema operativo, etc.). Hay cientos de cadenas de UserAgent conocidas - y más allá de esto, una serie de mecanismos para manipular esta cadena de UserAgent. Algunos navegadores (como Opera) incluso permiten al usuario seleccionar explícitamente el contenido de estas cadenas de UserAgent para hacerse pasar por un navegador diferente (porque muchos creadores de páginas web técnicamente incompetentes construyen su sitio en función del nombre de un navegador y excluyen innecesariamente algunos navegadores de él, o simplemente porque su usuario no quiere mostrar innecesariamente detalles sobre el equipo que usa, por el bien de mantener su privacidad).
Qué tan razonable sea servir páginas web comprimidas condicionalmente sobre la identidad de un cliente HTTP puede ser en algunos casos (como en lo que respecta a los numerosos errores de Netscape 4), aún así la desventaja de usar las cadenas de UserAgent como base de una negociación HTTP será que el contenido de este encabezado HTTP, por un lado, es demasiado variable para sacar conclusiones fiables de él y, por otro lado, contiene demasiados valores diferentes para que cualquier proxy de almacenamiento en caché pueda mantener en paralelo los resultados de solicitudes para la misma URL para todas estas variantes de negociación.
A partir de la versión 1.3.19.2a, mod_gzip está enviando un encabezado Vary: describiendo el encabezado HTTP User-Agent: como parámetro de la negociación, si se ha utilizado una directiva correspondiente en la configuración. Pero la probabilidad de que una solicitud sucesiva contenga un valor exactamente idéntico de User-Agent: (para que este cliente pueda, por lo tanto, recibir el contenido ya almacenado) es muy baja.
De hecho, el servidor HTTP trataría incluso grandes conjuntos de UserAgents (que se asumen funcionalmente equivalentes debido a su configuración) de manera idéntica durante la negociación - pero el encabezado Vary: no permite al servidor HTTP decir al proxy de almacenamiento en caché qué partes de las cadenas de UserAgent fueron evaluadas por el servidor HTTP como contenido significativo durante la negociación. El servidor proxy solo puede saber que el UserAgent ha jugado algún papel - y siendo consciente de esto, el proxy debe tratar a los UserAgents individuales como diferentes incluso si el servidor HTTP no actuaría de esta manera.
Así que usar reglas de filtro que evalúan el encabezado HTTP UserAgent llevará a desactivar totalmente cualquier almacenamiento en caché para los paquetes de respuesta creados de esta manera. El usuario de mod_gzip debería ser absolutamente consciente de este efecto - y por lo tanto usar otros métodos de filtrado (que tengan un número menor de valores diferentes posibles) si es posible, para proporcionar el mismo tipo de diferenciación entre estos Clientes HTTP.
Ubicación original de este documento:
Recibe nuevas publicaciones en tu bandeja de entrada.
No spam. Cancela la suscripción en cualquier momento.