Compressione contenuti · 12 min read · Sep 15, 2025
mod_gzip - servire contenuti compressi dal server web Apache - Pagina 9
Autore: Michael Schröpl
Compressione tramite negoziazione
Utilizzare una funzione di compressione configurabile come mod_gzip deve sempre essere una sorta di negoziazione dei contenuti, cioè servire contenuti diversi in modo condizionale per lo stesso URL richiesto, a seconda di informazioni specifiche all’interno delle intestazioni HTTP.
D’altra parte, HTTP consente il salvataggio temporaneo delle risposte alle richieste HTTP nelle cache, specialmente quando si utilizzano server proxy. Se ora
- un client HTTP invia una richiesta,
- la risposta corrispondente viene servita in forma compressa e memorizzata da un proxy e
- successivamente un altro client HTTP invia una richiesta per l’URL in questione,
allora il server proxy - non in possesso di ulteriori informazioni - ha un problema:
- Ha il diritto di servire il contenuto memorizzato nella cache anche a questo secondo client HTTP, oppure
- deve inoltrare la richiesta al server HTTP?
Solo il server HTTP può alla fine scoprire (basandosi sulla sua configurazione contenente le corrispondenti regole di filtro) se il secondo client HTTP può ricevere anche dati di risposta compressi.
A proposito, questo non è un effetto dell’utilizzo di una procedura di compressione da sola, ma un problema generale riguardante la memorizzazione nella cache dei dati HTTP il cui contenuto non può essere specificato in modo univoco da un URL all’interno della cache di un server proxy o server simili equipaggiati lungo il percorso di trasporto. Questo include procedure di negoziazione di qualsiasi tipo così come l’invio di informazioni aggiuntive nelle intestazioni HTTP, come dati di autenticazione o cookie.
Requisiti di prestazione
Certo, si può cercare di evitare il problema negando esplicitamente di memorizzare i dati della risposta corrispondente (utilizzando le intestazioni HTTP corrispondenti Expires: e Pragma: in HTTP/1.0 e Cache-Control: in HTTP/1.1) a tutti i server proxy esistenti lungo il percorso tra client e server.
Ma l’obiettivo della compressione è accelerare il trasferimento dei dati (riducendo il volume dei dati) - e memorizzare i dati serve lo stesso obiettivo (riducendo gli accessi al server HTTP). E un’ottimizzazione delle prestazioni non dovrebbe portare a un’altra che non è più utilizzabile, specialmente poiché queste due non si sostituiscono a vicenda ma possono complementarsi efficacemente nel caso in questione.
Informazioni sui parametri di negoziazione
La specifica HTTP contiene la definizione dell’intestazione Vary HTTP header dove il server HTTP può informare il server proxy su
- se la risposta è stata il risultato unico di una richiesta URL o
- se altri attributi di una richiesta per lo stesso URL potrebbero portare a risultati diversi.
Il suo valore può contenere un elenco di nomi di altre intestazioni HTTP il cui contenuto è stato rilevante per servire questa specifica risposta per una richiesta. Così il server HTTP può anche informare il server proxy su quali intestazioni HTTP hanno influenzato la decisione riguardo al contenuto servito.
Quando un server proxy inoltra una richiesta a un server HTTP e desidera memorizzare la risposta all’interno della sua cache in seguito, allora dovrebbe comunque essere in possesso delle intestazioni HTTP della richiesta originale quando arriva la risposta del server HTTP.
Ora, se il server HTTP contrassegna un contenuto condizionale di una risposta con la corrispondente intestazione Vary, allora
- il server proxy deve memorizzare nella sua cache non solo il contenuto di questa risposta ma tutte le informazioni rilevanti delle intestazioni HTTP (i cui nomi sono stati elencati nell’elenco dei valori dell’intestazione Vary della risposta) dalla richiesta, e
- non deve servire questo contenuto memorizzato nella cache come risposta a ulteriori richieste a meno che le informazioni delle intestazioni HTTP della richiesta successiva almeno ‘corrispondano’ a quelle della richiesta originale, cioè siano semantically identical to the original request’s values for each one of these headers.
Restrizioni risultanti per il server HTTP
Le spiegazioni precedenti hanno mostrato come un server proxy può gestire correttamente la consegna condizionale delle risposte HTTP (essendo il risultato di una Negoziato dei Contenuti) e con la massima utilizzazione del suo effetto di caching allo stesso tempo - a condizione che
- il server HTTP fornisca al server proxy informazioni sufficienti sui parametri di negoziazione e
- il server proxy sia in possesso delle informazioni corrispondenti nel caso di una richiesta successiva allo stesso URL da parte di un altro client HTTP.
Ma quest’ultima significa ora una restrizione per i gradi di libertà del processo di negoziazione. Perché se il server proxy deve decidere se può servire il contenuto della sua cache o meno esclusivamente basandosi su informazioni all’interno di una richiesta HTTP, allora le regole di negoziazione dei server HTTP non devono riferirsi a nulla di diverso dai contenuti delle intestazioni HTTP!
Ma sfortunatamente questa precondizione non è soddisfatta da mod_gzip, poiché delle sei classi di regole di filtro fornite
- due ‘legali’ (reqheader e uri) si riferiscono esclusivamente ai contenuti delle intestazioni HTTP ma
- quattro altre ‘illegali’ (rspheader, handler, file e mime) si riferiscono a informazioni che saranno disponibili solo durante la valutazione della richiesta da parte del server HTTP.
Quindi, se un server potenziato da mod_gzip utilizza una di queste regole di filtro ‘illegali’, allora il server proxy non può più essere in grado di decidere correttamente sull’applicabilità del suo contenuto della cache per rispondere a ulteriori richieste.
In tal modo non aiuta molto nemmeno al server proxy se mod_gzip notificasse al server proxy di essere evidentemente sovraccarico (fornendo un elenco completo delle classi di regole di filtro significative per questa richiesta all’interno di qualche intestazione Vary: se quella sarebbe anche legale). Tutto ciò che il server proxy potrebbe fare è utilizzare l’occorrenza di una di queste quattro classi di regole di filtro ‘illegali’ come criterio per non memorizzare il contenuto della risposta.
Questo da solo non sarebbe così male - finché il server HTTP si limita a utilizzare solo regole ‘legali’, sarebbe in grado di cooperare in modo ottimale con un server proxy.
Ma sfortunatamente farlo è impossibile con mod_gzip 1.3.19.1a.
L’integrazione di mod_gzip 1.3.19.1a nell’architettura Apache 1.3 avviene in un modo relativamente complesso:
- Nella fase di elaborazione 1, mod_gzip verifica se dovrebbe essere interessato a gestire i risultati di questa richiesta e prepararsi per essa - basandosi sulle regole di quattro classi (reqheader, uri, file e handler, cioè due classi di regole ‘legali’ e due ‘illegali’)
- Nella fase di elaborazione 2, mod_gzip verifica se ora dovrebbe effettivamente comprimere il contenuto di risposta (ora disponibile) - basandosi sulle regole di due classi (rspheader e mime, entrambe classi di regole ‘illegali’).
Per l’autorizzazione riuscita di una richiesta di compressione è necessaria almeno l’adempimento di una regola include da una delle due fasi (e il non adempimento di tutte le regole exclude).
Ma poiché entrambe le classi di regole include della fase 2 sono ‘illegali’, ogni elenco di classi di regole di filtro rilevanti per una compressione riuscita nell’attuale implementazione di mod_gzip deve almeno coprire una classe di regole ‘illegali’.
Pertanto, è impossibile fornire a un server proxy informazioni che può utilizzare per decidere sull’applicabilità di qualche contenuto della cache - le informazioni inviate sovraccaricheranno sempre la comprensione del server proxy.
Intestazioni Vary in mod_gzip 1.3.19.2a e successive
A partire dalla versione 1.3.19.2a, mod_gzip invia intestazioni Vary: - per ogni singola richiesta in cui il modulo è stato coinvolto almeno una volta (indipendentemente dal fatto che siano stati serviti dati compressi o meno).
A questo stato della ricerca per mod_gzip ogni richiesta (indipendentemente dal fatto che la risposta sia stata effettivamente servita in forma compressa) è potenzialmente una negoziazione:
- almeno riguardo all’intestazione Accept-Encoding HTTP, e
- possibilmente riguardo ad altre intestazioni HTTP (cioè tutte quelle che si verificano all’interno delle regole di filtro della classe reqheader)
Fino ad ora, mod_gzip non è ancora in grado di generare il miglior possibile, cioè il set minimo di intestazioni Vary: richieste - per questo sarebbe necessario riscrivere completamente la procedura di valutazione delle regole di mod_gzip.
Come primo passo, il modulo dalla versione 1.3.19.2a invia un’intestazione Vary: che contiene
- il valore Accept-Encoding così come
- i nomi di ogni intestazione utilizzata all’interno di qualsiasi regola reqheader,
perché ognuna di queste regole potrebbe fare la differenza per il risultato della negoziazione, e in ciascuno di questi casi il risultato dipenderebbe dai valori delle intestazioni HTTP ricevute. In alcuni casi questo potrebbe essere troppo (e quindi ostacolare massicciamente la memorizzazione efficiente dei contenuti), ma almeno è qualcosa da cui iniziare.
Come miglioramento a questa strategia, mod_gzip 1.3.26.1a non invia alcuna intestazione Vary: se la compressione della richiesta in questione è stata rifiutata a causa di una regola mod_gzip_item_exclude di tipo
- file,
- uri o
- handler
poiché la valutazione di questa regola non può essere stata dipendente dalle intestazioni HTTP ricevute, e quindi in questi casi effettivamente non ha avuto luogo alcuna negoziazione (riguardo a dimensioni che potrebbero contenere valori diversi per richieste HTTP diverse).
Se si desidera non inviare intestazioni Vary: per file che si è certi di non essere mai serviti in forma compressa a causa di altre regole di configurazione, si dovrebbe disattivare mod_gzip per questi.
Un esempio per non inviare intestazioni Vary: per immagini GIF che potrebbero essere memorizzate da qualche proxy come Squid 2.4 potrebbe apparire così:
mod_gzip_on No
Per le versioni future rimangono aperti i seguenti compiti:
- Riconoscere in tutti i casi possibili che la reazione alla richiesta corrente non può mai causare l’invio di dati compressi poiché si attiva qualche regola mod_gzip_item_exclude indipendente dagli attributi della richiesta.
- Riconoscere che è avvenuta qualche negoziazione che non può essere descritta da un elenco di nomi di intestazioni HTTP - in questo caso Vary: * dovrebbe essere inviato (e la documentazione per mod_gzip dovrebbe sottolineare esplicitamente che queste direttive devono essere utilizzate solo se assolutamente necessario poiché il loro utilizzo avrà un effetto negativo sul lavoro dei proxy di caching).
- Controllare se sono possibili configurazioni in cui solo un sottoinsieme di nomi di intestazioni da tutte le regole reqheader è richiesto in un’intestazione Vary: - meno nomi ci sono, meno varianti devono essere memorizzate nella cache del proxy in parallelo.
Negoziazione su altre dimensioni oltre le intestazioni HTTP
In casi molto speciali, cioè quando si utilizzano determinate direttive di configurazione, mod_gzip effettua alcune negoziazioni su dimensioni che non possono nemmeno essere espresse in termini di nomi di intestazioni HTTP. Questo si applica alle direttive
- mod_gzip_min_http (versione HTTP minima richiesta) così come
- mod_gzip_handle_methods (metodi HTTP da gestire)
In entrambi i casi, mod_gzip non può spiegare a un proxy cosa è stato fatto dicendo i nomi delle intestazioni HTTP. La reazione appropriata secondo la specifica HTTP/1.1 è inviare l’intestazione Vary: *.
mod_gzip 1.3.26.1a invia un’intestazione Vary: ** se è stata utilizzata la direttiva mod_gzip_min_http*.
Per quanto riguarda la direttiva mod_gzip_handle_methods, attualmente sembra non essere ancora del tutto chiaro se due richieste HTTP per lo stesso URI ma utilizzando metodi HTTP diversi chiedano effettivamente la stessa entità HTTP - questo deciderà se un’intestazione Vary: * dovrà essere inviata anche quando si utilizza questa direttiva, e sarà un problema da risolvere nelle prossime versioni.
Ma poiché in questo caso un server proxy non può comprendere il tipo di negoziazione effettuata, non ha il diritto di memorizzare risposte contrassegnate da questo segno all’interno di qualche cache.
Pertanto, l’utilizzo di una di queste direttive disabilita completamente la memorizzazione nella cache di ciascuna risposta inviata da questo server HTTP, sia in forma compressa che non compressa. Pertanto, ti consigliamo di non utilizzare più una di queste direttive.
L’UserAgent come caso speciale
Memorizzare varianti di diversi parametri di negoziazione in parallelo in una cache proxy può essere ragionevole se solo pochi valori possibili possono effettivamente verificarsi - come nel caso di Content-Encoding. Se ci sono un gran numero di valori possibili, allora una memorizzazione parallela di varianti non è più fattibile.
Esattamente questo si applica al nome UserAgent come identificazione del client HTTP. Ogni sottoversione di un browser invia una complessa stringa UserAgent che contiene non solo nome e versione dei browser, ma ulteriori informazioni (lingua nazionale, nome e versione del sistema operativo, ecc.). Ci sono centinaia di stringhe UserAgent conosciute - e oltre a questo un numero di meccanismi per manipolare questa stringa UserAgent. Alcuni browser (come Opera) consentono persino all’utente di selezionare esplicitamente il contenuto di queste stringhe UserAgent per fingersi un browser diverso (perché molti creatori di pagine web tecnicamente incompetenti costruiscono il loro sito basandosi sul nome di un browser ed escludono inutilmente alcuni browser, o semplicemente perché il loro utente non vuole mostrare inutilmente dettagli sull’attrezzatura del computer che utilizza, per mantenere la propria privacy).
Quanto sia ragionevole servire pagine web compresse in modo condizionale sull’identità di un client HTTP possa mai essere in alcuni casi (come rispetto ai numerosi bug di Netscape 4), rimane il fatto che il lato negativo dell’utilizzo delle stringhe UserAgent come base di una negoziazione HTTP sarà che il contenuto di questa intestazione HTTP da un lato è troppo variabile per trarre conclusioni affidabili e dall’altro contiene troppi valori diversi affinché qualsiasi proxy di caching possa mai essere in grado di mantenere in parallelo i risultati delle richieste per lo stesso URL per tutte queste varianti di negoziazione.
A partire dalla versione 1.3.19.2a, mod_gzip invia un’intestazione Vary: che descrive l’intestazione HTTP User-Agent: come parametro della negoziazione, se è stata utilizzata una corrispondente direttiva nella configurazione. Ma la probabilità che una richiesta successiva contenga un valore User-Agent: esattamente identico (in modo che questo client possa quindi ricevere il contenuto già memorizzato) è molto bassa.
In realtà, il server HTTP tratterebbe anche grandi insiemi di UserAgents (che si presume siano funzionalmente equivalenti a causa della sua configurazione) in modo identico durante la negoziazione - ma l’intestazione Vary: non consente al server HTTP di comunicare al proxy di caching quali parti delle stringhe UserAgent sono state valutate dal server HTTP come contenuto significativo durante la negoziazione. Il server proxy può solo sapere che l’UserAgent ha giocato qualche ruolo - e essendo consapevole di questo, il proxy deve trattare gli UserAgents individuali come diversi anche se il server HTTP non agirebbe in questo modo.
Quindi l’utilizzo di regole di filtro che valutano l’intestazione HTTP UserAgent porterà a disabilitare completamente qualsiasi memorizzazione nella cache per i pacchetti di risposta creati in questo modo. L’utente di mod_gzip dovrebbe essere assolutamente consapevole di questo effetto - e quindi utilizzare altri metodi di filtro (avendo un numero minore di valori diversi possibili) se possibile, per fornire lo stesso tipo di differenziazione tra questi Client HTTP.
Posizione originale di questo documento:
Ricevi i nuovi post nella tua casella di posta.
Nessuno spam. Disiscriviti in qualsiasi momento.