Модуль mod_deflate
(2086 всего слов в этом тексте)
(прочитано: 12 раз)
Модуль mod_deflate кодирует HTTP-ответ методами gzip и deflate, что позволяет уменьшить размер передаваемых данных в 2 и более раз. mod_deflate представляет из себя собственно модуль и набор патчей для Apache и модуля mod_charset (Russian Apache).
СодержаниеУстановка
Как это работает
Некоторые рекомендации
Какие бывают методы кодирования
Директивы
DeflateCompLevel
DeflateDisableRange
DeflateEnable
DeflateHTTP
DeflateIdleCheck
DeflateMinIdle
DeflateMinLength
DeflateOrder
DeflateProxied
Что можно записать в лог
Переменные среды
Известные ошибки и особенности
Броузеры, что они умеют
Прокси-сервера
Установка
Дистрибутив необходимо распаковать, перейти в каталог с исходными текстами и выполнить команду ./configure, указав ей путь к исходными текстам Apache. После конфигурирования нужно выполнить команду make:
tar zxf mode_deflate-x.x.x.tar.gz
cd mod_deflate-x.x.x
./configure --with-apache=<apache_dir>
make
Команда make накладывает патчи на исходные тексты Apache и копирует mod_deflate.c в каталог <apache_dir>/src/modules/extra/. На FreeBSD можно указать параметр --with-idle-check для проверки уровня загрузки процессора. При сборке Apache модуль необходимо активировать:
cd <apache_dir>
./configure
...
--activate-module=src/modules/extra/mod_deflate.o
...
Как это работает
Для того, чтобы ответ был сжат, в запросе прежде всего должен быть заголовок "Accept-Encoding", в котором указан метод gzip или deflate. На данный момент (2001 год) по обобщённым данным нескольких систем сбора статистики в Рунете около 90-93% всех запросов выполняется броузерами MSIE 5.x и 4.x, понимающими gzip и deflate и около 5-7% - броузерами Netscape 4.x, понимающими gzip.
Кроме того, запрос не должен проходить через транзитные прокси-сервера, поскольку нельзя определённо сказать, умеют ли они корректно кэшировать компрессированые ответы. Например, неумеющий правильно кэшировать сжатые ответы прокси-сервер может передать закэшированный в сжатом виде ответ клиенту, непонимающему подобное кодирование. Наличие прокси-серверов проверяется по заголовку "Via". С этим же связано ограничение на версию протокола HTTP - сжатие выполняется, только если версия запроса не ниже 1.1, так как только в этой версии прокси-сервер обязан устанавливать заголовок "Via". Для запроса версии 1.0 нельзя определённо утверждать, что запрос не проходил через прокси-сервера.
Существует ещё несколько условий для сжатия ответа:
ответ должен иметь тип "text/*" (как правило, это "text/html" или "text/plain"),
код ответа должен быть равен 200 (HTTP_OK),
ответ не должен уже иметь заголовка "Content-Encoding",
и в запросе не должен запрашиваться только заголовок (HEAD).
Если все описанные выше условия соблюдены, то в ответ добавляется заголовок "Content-Encoding: gzip" или "Content-Encoding: deflate", а тело ответа сжимается указанным методом. Кроме того, в сжатом ответе удаляется заголовок "Content-Length", поскольку длина сжатого ответа неизвестна на момент передачи заголовков. В отсутствие заголовка "Content-Length" и при запросе версии HTTP/1.1 Apache передаёт ответ чанками (chunks) и добавляет заголовок "Transfer-Encoding: chunked". Необходимо заметить, что в этом случае соединение может находится в состоянии keep-alive после передачи ответа. Если же запрос версии 1.0, то при отсутствии заголовка "Content-Length" соединение закрывается сразу же после передачи ответа.
Некоторые рекомендации
Для того, чтобы ответы кодировались методом gzip достаточно одной директивы DeflateEnable on. Кроме того, из-за ошибки в MSIE 4.x рекомендуется использовать директиву DeflateDisableRange "MSIE 4."
Однако при такой настройке ответы на запросы от Netscape 4.x сжиматься не будут, поскольку Netscape 4.x делает запросы версии 1.0. Поскольку сейчас около 90-93% запросов выполняется броузерами MSIE 4.x и 5.x и около 5-7% - броузером Netscape 4.x, то часть из оставшихся 2-3% запросов может выполняться броузерами, которые не понимают gzip в качестве "Content-Encoding". Если эти запросы не представляют для Вас интереса, то можно добавить такие директивы
DeflateHTTP 1.0
DeflateProxied on
и получить уменьшение исходящего трафика HTML-файлов в два-три раза, тогда как при настройках по умолчанию уменьшение не так заметно из-за того, что около трети всех запросов выполняется через прокси-сервера.
Не рекомендуется использовать метод deflate по причинам, изложенным чуть ниже.
При возникновении проблем с тем или иным броузером, декларирующим понимание какого-либо метода, но не понимающим его на самом деле, в качестве временного решения рекомендуется использовать запрещающие переменные среды.
Какие бывают методы кодирования
В описании протокола HTTP 1.1 (RFC 2616) описаны 4 метода кодирования - gzip, deflate, compress и identity. В описании протокола HTTP 1.0 (RFC 1945) описаны 2 метода кодирования - x-gzip и x-compress, являющихся предшественниками и полными аналогами методов gzip и compress. mod_deflate поддерживает только два метода кодирования - gzip и deflate и не поддерживает все остальные, в частности, метод x-gzip.
gzip
Два метода кодирования, gzip и deflate, используют один и тот же метод сжатия данных - deflate (RFC 1951), реализуемый библиотекой zlib (RFC 1950). В методе gzip (RFC 1952) перед сжатым потоком добавляется 10-байтный заголовок. Кроме того, после сжатого потока добавляется контрольная сумма CRC32 и длина несжатых данных, в сумме занимающие 8 байт. Тело HTTP-ответа в этом случае такое же, как если бы оно было сжато программой gzip. Это самый распространённый метод - в частности, его понимают броузеры Netscape 4.x-6.x, Mozilla, MSIE 4.x-6.x, Opera 4.x-5.x и Lynx 2.6-2.8.x.
deflate
С методом кодирования deflate дела обстоят сложнее. В описании протокола HTTP 1.1 (RFC 2616) deflate описан так:
The "zlib" format defined in RFC 1950 in combination with the "deflate" compression mechanism described in RFC 1951.
Что, по-видимому, должно означать, что перед сжатым потоком должно быть 2 байта заголовка zlib, а после сжатого потока - контрольная сумма Adler32 (4 байта). Однако в броузерах MSIE 4.x-6.x,Opera 4.x-5.x,Netscape 6.x и Mozilla метод deflate реализован иначе - он представляет из себя только сжатый поток без заголовка и контрольной суммы. Именно этот вариант реализован в модуле mod_deflate. Кроме того, известен один броузер, Konqueror, в котором метод deflate реализован с ошибками и, начиная с версии "Konqueror 2.1 post BETA >= 20010128", этот броузер просто не указывает метод deflate в заголовке "Accept-Encoding". Существование двух возможных реализаций и реализаций с ошибками делает ненадёжным использование метода deflate.
compress
Этот метод кодирования используют метод сжатия данных, реализованный в программе compress, то есть, тело HTTP-ответа в этом случае такое же, как если бы оно было сжато этой программой. Этот метод понимают Lynx 2.6-2.8.x, Netscape 4.x-6.x и Mozilla.
identity
Этот метод кодирования никак не изменяет тело HTTP-ответа.
Директивы
Директива DeflateCompLevelSyntax: DeflateCompLevel 1 .. 9
Default: DeflateCompLevel 1
Context: server config, virtual host, directory, .htaccess
Устанавливает определённый в библиотеке zlib уровень сжатия от 1 до 9. Хотя уровень 1 наименее ресурсоёмок, тем не менее, он, как правило, позволяет уменьшить объём передаваемых файлов HTML в 2-4 раза. Увеличение уровня сжатия до 9 обычно не даёт такого впечатляющего результата, тo есть, если, например, при уровне 1 данные сжимаются в 4 раза, то при уровне 9 они сожмутся лишь в 5 раз. Насколько сжимается тот или иной файл в зависимости от уровня сжатия, Вы можете проверить с помощью программы gzip, указав ей параметр от -1 до -9.
В библиотеке zlib определён ещё один уровень - 0 (store), при котором сжатие не выполняется, но в контексте протокола HTTP он не имеет смысла, поскольку всегда можно передавать данные, вообще не используя сжатие.
Директива DeflateDisableRangeSyntax: DeflateDisableRange строка
Default: нет
Context: server config, virtual host, directory, .htaccess
Задаёт строку, при нахождении которой в заголовке "User-Agent" запрещается передача части ответа (range) в случае, если ответ может быть кодирован методом gzip или deflate. Таких директив может быть несколько. Если ответ не может быть кодирован методом gzip или deflate, то части (range) для данного броузера не запрещаются. Рекомендуется устанавливать такую директиву
DeflateDisableRange "MSIE 4."
Директива DeflateEnableSyntax: DeflateEnable on|off
Default: DeflateEnable off
Context: server config, virtual host, directory, .htaccess
Разрешает или запрещает кодирование методом gzip или deflate.
Директива DeflateHTTPSyntax: DeflateHTTP 1.0|1.1
Default: DeflateHTTP 1.1
Context: server config, virtual host, directory, .htaccess
Устанавливает минимальную версию протокола HTTP в запросе, при которой разрешается кодирование методом gzip или deflate.
Директива DeflateIdleCheckSyntax: DeflateIdleCheck число
Default: DeflateIdleCheck 1
Context: server config
Задаёт интервал проверки уровня загрузки процессора в секундах. Эта директива доступна только на FreeBSD 3.x и выше при указании параметра --with-idle-check при конфигурации.
Директива DeflateMinIdleSyntax: DeflateMinIdle 0 .. 100
Default: DeflateMinIdle 0
Context: server config
Задаёт минимальный уровень бездействия процессора в процентах, при котором разрешается кодирование методом gzip или deflate. Эта директива доступна только на FreeBSD 3.x и выше при указании параметра --with-idle-check при конфигурации.
Директива DeflateMinLengthSyntax: DeflateMinLength число
Default: DeflateMinLength 0
Context: server config, virtual host, directory, .htaccess
Устанавливает минимальный размер тела ответа в байтах, при котором разрешается кодирование методом gzip или deflate. Размер определяется из заголовка "Content-Length", если это заголовок отсутствует, то кодирование выполняется независимо от размера ответа.
Директива DeflateOrderSyntax: DeflateOrder метод [метод]
Default: DeflateOrder gzip
Context: server config, virtual host, directory, .htaccess
Задаёт приоритет при выборе метода кодирования. Например, директива "DeflateOrder deflate gzip" делает метод deflate более приоритетным, чем gzip. Этой же директивой можно устанавливать только один метод кодирования. По умолчанию используется только метод gzip, поскольку использование метода deflate на данный момент ненадёжно.
Директива DeflateProxiedSyntax: DeflateProxied on|off
Default: DeflateProxied off
Context: server config, virtual host, directory, .htaccess
Разрешает или запрещает кодирование методом gzip или deflate для проксированных запросов. Такие запросы определяются по наличию заголовка "Via".
Что можно записать в лог
Судить о том, был ли сжат тот или иной ответ, каким методом и насколько можно с помощью заметок (notes):
defl_m - один символ, означающий метод кодирования - "d" - deflate, "g" - gzip. Кроме того, если проверяется загрузка процессора, то возможно ещё одно значение "b" - blocked, означающее, что кодирование возможно, но запрещено из-за загрузки процессора.
defl_i - размер несжатого (input) ответа.
defl_o - размер сжатого (output) ответа. Необходимо заметь, число переданных байт (%b) по протоколу HTTP/1.1 будет больше, поскольку в %b учитывается служебная информация для кодирования чанками (chunks).
defl_r - число с точностью до двух знаков после запятой, показывающее степень (ratio) сжатия. Считается как defl_i / defl_o.
В логах заметки можно использовать в виде %{defl_r}n.
Переменные среды
Кодирование тем или иным методом можно запретить с помощью переменных среды "no_deflate" и "no_gzip", устанавливаемых директивами SetEnvIf, BrowserMatch и им подобным, например:
BrowserMatch "Konqueror" no_deflate
BrowserMatch "rv:0.9.1) Gecko/" no_gzip no_deflate
На самом деле, указывать именно эти строки не нужно, так как, начиная с версии 1.0.7, mod_deflate содержит их в коде.
Известные ошибки и особенности
mod_deflate не сжимает ответы, прошедшие через mod_proxy, поскольку mod_proxy для отдачи ответа клиенту не использует функцию ap_send_http_header(). В то же время, ответы mod_proxy, вставляемые с помощью mod_rewrite в SSI-документы, сжимаются.
Текст, выведенный с помощью функций ap_rprintf() и ap_vrprintf(), не перекодируется Russian Apache. Это связано с тем, что Russian Apache, обрабатывая эти функции, работает напрямую с BUFF вместо того, что бы использовать функции ap_b*() и портит сжатый поток. Поэтому для этих функций запрещается перекодирование. На самом деле, эта особенность не должна повлиять на что-либо, поскольку на данный момент функции ap_rprintf() и ap_vrprintf() не используются для вывода каких-либо текстов на русском языке. Функция ap_rprintf() активно используется в mod_status и mod_info, и незначительно в mod_include для вывода fsize, в mod_autoindex для вывода размеров иконок и в mod_jserv для вывода статуса.
mod_deflate не учитывает веса методов кодирования, указанных в заголовке "Accept-Encoding". Вместо этого приоритет методов задаётся с посредством директивы DeflateOrder.
Поскольку для работы mod_deflate необходимо патчить тексты Apache, модуль должен быть статически слинкован с Apache.
Для сборки модуля необходима библиотека zlib, что, в принципе, не является проблемой для большинства Unix-платформ.
Модуль, возможно, будет собираться на не-Unix платформах, но никаких телодвижений по портированию не делалось.
Броузеры, что они умеют
Ниже приводится список броузеров с указанием версии протокола и методов кодирования, указываемые в заголовке "Accept-Encoding". Для более или менее распространённых броузеров в скобках приводиться приблизительный процент их использования на данный момент (2001 год). Для некоторых броузеров даны комментарии о тех или иных ошибках или особенностей обработки сжатых запросов. Отсутствие комментария не означает, что ошибок нет, скорее о них пока не известно.
MSIE 4.x (10-14%), 5.x (76-79%) и 6.x, кроме версий под Macintosh
HTTP/1.1, "gzip, deflate"
MSIE 4.x кэширует принятые ответы в сжатом виде, поэтому если приём сжатого ответа прервать, а затем повторить снова, то MSIE делает запрос с прерванного места, указывая в заголовке "Range" смещение, равное длине полученного сжатого ответа. Если ему передать несжатый остаток, то MSIE считает, что весь ответ не сжат и показывает закэшированную часть в сжатом виде, а следом за ней вновь полученную часть. Как правильно передавать остаток в сжатом виде для MSIE 4.x, сказать сложно, проще запретить передачу по частям в таких случаях. Поэтому разумным компромиссом является директива DeflateDisableRange "MSIE 4."
MSIE 4.x некорректно обрабатывает сжатый поток, если длина запрашиваемого URL без учёта префикса "http://" больше по-видимому 253 символов. В этом случае MSIE 4.x долго ждёт ответа от сервера, зависает или завершается с ошибкой. Поэтому, начиная с версии 1.0.7, mod_deflate запрещает кодирование методами gzip или deflate, если заголовок "User-Agent" содержит строку "MSIE 4" и длина строки запроса больше 200.
Netscape 3.x, 4.0-4.05, версии под UNIX и PowerPC Macintosh
HTTP/1.0
Netscape 3.x хотя и не передает заголовок "Accept-Encoding", но понимает метод x-gzip.
Netscape 4.0-4.05 хотя и не передает заголовок "Accept-Encoding", но понимает методы gzip и x-gzip.
Netscape 4.06-4.08, 4.5-4.7x (3-5%)
HTTP/1.0, "gzip"
Эти версии также понимают методы x-gzip и x-compress.
Версии Netscape 4.x под Windows кэшируют принятые ответы в сжатом виде, но не расжимают их при печати или предварительном просмотре перед печатью.
Netscape 6.x, Mozilla m14-m18, 0.6-0.9.2
HTTP/1.1, "gzip,deflate,compress,identity"
Эти версии также понимают методы x-gzip и x-compress.
Версии Netscape 6.1b1 и Mozilla 0.9.1 не воспринимают заголовок "Content-Encoding" с пробелом в конце заголовка и показывают ответ в сжатом виде. Поэтому, начиная с версии 1.0.6, mod_deflate запрещает кодирование методами gzip или deflate, если заголовок "User-Agent" содержит строку "rv:0.9.1) Gecko/".
Mozilla 0.9.3
HTTP/1.1, "gzip, deflate, compress;q=0.9"
Эта версия также понимают методы x-gzip и x-compress.
Opera 4.x-5.x
HTTP/1.1, "deflate, gzip, x-gzip, identity, *;q=0"
Lynx 2.6-2.8.x
HTTP/1.0, "gzip, compress"
Эти версии также понимают методы x-gzip и x-compress.
Konqueror 2.0.x
HTTP/1.1, "x-gzip; q=1.0, x-deflate, gzip; q=1.0, deflate, identity"
Обработка метода gzip в Konqueror реализованa неэффективно - сжатый ответ записывается во временный файл, после чего файл открывается функцией gzdopen() и считывается функцией gzread(). Что касается метода deflate, то его реализация просто не работает. Создаётся впечатление, что разработчики не понимали то, что они писали - сначала сжатый ответ записывается во временный файл, затем он частями считывается (зачем вообще файл!?) и передаётся функции inflate(), что однако не приводит к желаемому результату, поскольку функция inflateInit2() не вызывается вообще.
В связи с этим, начиная с версии 1.0.7, mod_deflate запрещает кодирование методом deflate, если заголовок "User-Agent" содержит строку "Konqueror".
Konqueror 2.1.x
HTTP/1.1, "x-gzip; q=1.0, gzip; q=1.0, identity"
Начиная с версии "Konqueror 2.1 post BETA >= 20010128", в заголовке "Accept-Encoding" не указывается deflate и x-deflate, но реализация осталась прежней.
Macromedia FlashPlayer 4.x-5.x
Не понимает сжатые ответы, полученные через броузер с помощью функции getVariables().
Прокси-сервера
Около трети всех запросов выполняются через прокси-сервера. Ниже приводится список некоторых прокси-серверов. Для более или менее распространённых серверов в скобках указан приблизительный процент их использования на данный момент (2001 год).
Squid (около 70%)
Не умеет правильно кэшировать сжатые запросы.
MS Proxy 2.0 (IIS 4.0) (около 15%)
Не умеет правильно кэшировать сжатые запросы.
Oops (3%)
Начиная с версии 1.5.0, для клиентов, непонимающих кодирование методом gzip, Oops отдаёт кэшированные сжатые ответы в разжатом виде.
(C) 2001, Igor Sysoev