Одни люди ищут - причины, другие - возможности, выигрывают последние

Сжатие gzip для JavaScript и CSS

В последние время многие озаботились оптимизацией и убыстрением загрузки веб страниц, и это правильно. Аппетиты растут, но всему есть предел, уже никого, я думаю, не волнует вопрос: "Жать или не жать?", ответ однозначен - "Сжимать необходимо".

Я уже писал про оптимизацию и сжатие CSS и JavaScript, где вскольз упоминал про возможность сжатия на лету через поддержку gzip со стороны сервера и клиента. Вот про эту тему поговорим сегодня более подробнее.

Все современные браузеры, включая даже самый "любимый" IE6, могут работать с gzip содержимым. Когда Вы посылаете запрос на отображение веб страницы, браузер говорит серверу, что он может принимать сжатое содержимое. В заголовке запроса это выглядит как: Accept-Encoding: gzip,deflate. В ответ, сервер может выдавать сжатое содержимое текстовых данных, которыми являются HTML страницы (в том числе и сгенерированные динамически), CSS файлы, файлы JavaScript и т.п.

Веб сервер, а мы будем говорить про Apache, должен уметь делать gzip сжатие и определять, для какого отправляемого содержимого он будет это делать.

Вообще странно, что в Интернет полно советов по использованию gzip сжатия через какие-то "магические" действия, с применением Rewrite Engine и скриптов обработки, генерящих сжатое содержимое CSS и JavaScript, мне несовсем понятны подобные действия (за исключенем, пожалуй, каких-то ограничений хостинг провайдера) по излишней изобретательности и лишней нагрузки на сервер, когда сам Apache специально заточен под работу с gzip.

В Apache, отправкой сжатого содержимого занимается модуль mod_deflate, который может быть подключен как в Windows (LoadModule deflate_module modules/mod_deflate.so), так и, естественно, скомпилирован в Linux (--enable-deflate).

А вот определением того, что жать, а что нет, должны заниматься правила фильтрации сжимаемого содержимого по запросу клиентского браузера или его MIME типу. Более доступно, это можно описать следующим правилом: Если получаемый от клиента запрос содержит разрешение на сжатие - Accept-Encoding: gzip,deflate или отправляемое содержимое несет в себе лишь текстовую информацию, то отправляемый контент однозначно необходимо жать. До Apache версии 2.1 этим занималось семейство директив AddOutputFilter, а с версии 2.1 предпочтение отдается более гибкому модулю mod_filter. Вот его мы и рассмотрим.

Как пример, один из вариантов, когда мы хотим сжимать отправляемое (resp=) содержимое, MIME тип которого (Content-Type) содержит в себе слова text или javascript, выглядит вот так:

FilterDeclare gzip CONTENT_SET
FilterProvider gzip deflate resp=Content-Type $text/
FilterProvider gzip deflate resp=Content-Type $javascript
FilterChain gzip

Мне же по душе вариант, когда клентский браузер сам говорит (req=), что он может принимать сжатое содержимое (Accept-Encoding содержит слово gzip):

FilterDeclare gzip CONTENT_SET
FilterProvider gzip deflate req=Accept-Encoding $gzip
FilterChain gzip

Рассмотрим фильтр более подробно:
- Первая строка определяет произвольное имя фильтра (gzip) и его тип, т.е. с чем мы далее будем работать (CONTENT_SET).
- Вторая, определяет обработчика того, с чем мы работаем по заданному условию. В нашем случае обработчиком будет deflate, вызываемый в том случае, если в заголовке запроса (req=), в параметре Accept-Encoding присутствует слово gzip.
- И третьей строкой мы запускаем в действие составленный нами фильтр с именем gzip в любом из контекстов сервера.

По моему все просто и доступно (контекст директив доступен через .htaccess). А теперь результат:
Как пример: размер packed версии jQuery 1.2.3, равный 29848 байт, после обработки gzip составил меньше 15K (14833 байта, можно сделать его еще меньше, до 14652 байт, отрезав комментарии).

Как я говорил, такая схема работает на ура даже с IE6, в чем вы можете убедиться просмотрев заголовки запросов и ответов через ieHTTPHeaders

[08.04.2008] Обновлено:

Прошел месяц, пора подводить итоги. Что-ж, результат замечательный, сжатие работает на ура и выигрыш в его использовании весьма ощутим, особенно на медленных дайловых соединениях. Все это дело тестировалось на сервере с четырьмя десятками разношерстных веб ресурсов. Специально обзванивал клиентов работающих через прокси сервера и друзей увлекающихся серфингом с различными веб браузерами. В итоге, с лучшей стороны себя зарекомендовало следующее звено фильтров, его я и рекомендую:

FilterDeclare gzip CONTENT_SET
FilterProvider gzip deflate resp=Content-Type $text/
FilterProvider gzip deflate resp=Content-Type $javascript
FilterProvider gzip inflate req=Accept-Encoding !$gzip
FilterChain gzip

Как видно добавилась еще одна полезная строчка контролирующая разрешение на сжатие со стороны клиента, т.е. если клиент не может разжимать (req=Accept-Encoding !$gzip), то отдаем ему несжатый контент (inflate).

И еще, насчет замечаний в комментариях про сложность проблемы и необходмиость поддержки древних (или странных) клиентов. Ситуация напоминает мне баянистое высказывание: "Он был настолько скуп, что лазил по порно сайтам с отключенными картинками" :), помоему проблема несколько преувеличена и скорее должна быть проблемой клиента, чем "плясками" на сервере, тем более странный контингент незначителен.

14 комментариев на статью:
  • sillysunnybear:

    боюсь разочаровать, но проблема несколько более глубокая, чем заявлено. Предложенное решение описано здесь
    http://webo.in/articles/habrahabr/07-gzip-all/

  • admin:

    Спасибо, протестирую, сделаю выводы.

    Хотя странно, если браузер сам говорит, что он может: Accept-Encoding: gzip,deflate, а сам не может выполнить корректную gzip обработку, это просто «замечательный» браузер какой-то…

  • Anonymous:

    Обратный процесс как реализовать ?
    Вытаскиваю страницу сервером для дальнейшей её обработки, а она сжата «qzip». В итоге получить корректный код — не удаётся. «Донор» — не хочет реагировать на подмену Хедера, и постоянно выдаёт данные в зжатом виде. Как получить/распаковать эти данные на своем сервере ? (Очень нужно)
    (Apache + Perl)
    О процессах сжатия много чего написано, а вот о том, как распаковать на Apache….

  • admin:

    Не совсем проникся Вашей задачей, но навскидку вижу два решения:
    -Либо регулировать клиентский запрос через Accept-Encoding, что-бы Apache возвращал inflate содержимое.
    -Либо на принимающей стороне скрипта делать gzinflate (к сожалению не знаю как это называется в Perl)

  • Золотой:

    Попробовал последний вариант на своем сайте. Все работает. YSlow не ругается на несжатые js файлы. Спасибо.

  • sammerset:

    А как вообще определить, используется сжатие на сервере уже или нет?

  • sammerset:

    К примеру этот сайт? — http://www.secumart.com.ua

  • Dmitriy:

    Хоть тема и старая, но не ответить не могу. Спасибо огромное автору за столь оригинальное решение, работает на УРА на всех браузерах (IE 5.0+, Opera 7+, FF2+, Chrome, Safari). Этот способ намного удобнее и легче, чем описанный на http://webo.in/articles/habrahabr/07-gzip-all/.

    2 sammerset. Проверить работу сжатия можно на сайте http://www.pipeboost.com/

  • liveintv:

    Спасибо за описание ! А действительно как узнать есть ли сжатие на сервере?:

  • 4idroid:

    Ну наконец то получилось!

  • Иван:

    Даа, тут без ста грамм не разберешься. Придется пока заморозить эту проблему

  • SEO admin:

    Благодаря автору смог включить у себя сжатие!
    Век бы не знал что это такое и как сделать.
    реально ускорилось благодаря сжатию !
    Рекомендую всем!

Ответить
Обязательные поля помечены *