Наткнулся на кучу интересных статей на webo.in и зачитался. Решил применить описанное там на реальном проекте. Вот что получилось. Проектик маленький — сайт моих друзей Bookcare. Они делают обложки для книг, а их сайт — мой «проект выходного дня».
Основная часть контента — это изображения обложек, которые хранятся в формате jpeg. Значит действия над этой частью оптимизации сводятся к оптимизации самих картинок и настройке кеширования.
Для оптимизации картинок я использовал jpegtran, однако проблема с ним была в том, что он не может обработать сразу всю папку — только по одному файлу. Другая проблема, что использовать входной файл в качестве выходного (просто перезаписать оптимизированный файл в старый) невозможно.
Я решил эту проблему небольшим скриптиком и, хотя я не очень силен в shell-скриптах, он работает и достаточно удобно производить замены. Итак, я создал в домашней папке скрипт jp.sh:
jpegtran -copy none -optimize -perfect "$1" > "оsh_conv_$1" mv "$1" raw/ mv "оsh_conv_$1" "$1"
А затем выполнял простую последовательность:
mkdir raw
find *.jpg -depth 0 -type f -iregex ".*\.jpg" -exec ~/s.sh {}После этого в папке с картинками уже лежат оптимизированные джепеги, и создается новая папка raw/, содержащая исходные файлы. Папочка raw/ очень пригодилась, когда оказалось, что скриптик мой не отрабатывал на файлах с именами, содержащими не латиницу (файлы просто обнулялись). Сейчас все работает.
Итак, после того, как картинки удобным образом оптимизированы, надо было настроить кеширование. Я добавил выдачу ETag. Это просто и описано на webo.in. Делается добавлением одной строки в .htaccess
FileETag MTime Size
Вообще-то надо еще настроить выдачу заголовков Expires, но это тоже делается несложно.
После разборок с картинками, они стали весить на 34% меньше, что на странице Каталога ускорило загрузку почти настолько же, так как основной контент — это именно картинки.
Далее я прошелся по хтмльной выдаче. Верстка не моя, по этому, я пока не полез в оптимизацию разметки, но базовые фичи сделал: убрал переносы строк, табы и повторяющиеся пробелы.
Далее интересней. Захотелось, чтобы все (даже пхпшные) странички выдавали Last-Modified и правильно откликались на If-Modified-Since.
Взглянул на главную страницу и понял, что там выводятся только новости и последние поступления (из динамического контента). Соответственно получил дату последней новости, дату последнего поступления, получил максимальную и обработал следующим образом:
// $md - Штамп даты последнего изменения
$modified = gmdate("D, d M Y H:i:s",$md)." GMT";// Приводим к HTTPшному формату - "Mon, 20 Dec 2004 09:34:19 GMT";
$hdr = '';
$headers = apache_request_headers();
foreach ($headers as $header => $value) {
if (eregi('If-Modified-Since', $header)) {$hdr = $value;}
}
if ($hdr === $modified) {
header ("HTTP/1.1 304 Not Modified ");
header ("Last-Modified: ". $modified);
header ("Expires:");
header ("Cache-Control:");
exit();
}
header ("Last-Modified: $modified");
header ("Expires:"); // обнуляем ненужные заголовки
header ("Cache-Control:");Надо отметить, что время в Last-Modified надо указывать всегда в GMT, то есть по Гринвичу.
Теперь страничка загружается один раз, а далее мы видим ответ 304 Not Modified.
Еще одно важное замечание — заголовок Last-Modified надо выдавать всегда, иначе страница будет загружаться через раз, так как в ответе 304 не было указано Last-Modified. Такое поведение было замечено за FF3.
Затем добрался до выдачи css в виде архивов. Тут меня не устроило решение, которое было дано на webo.in, так как на серваке bookcare.ru нет mod_headers. Я использовал достаточно спорный метод, но в рамках данной задачи, я считаю, вполне законный:
RewriteEngine On
AddEncoding gzip .css
RewriteCond %{HTTP:Accept-encoding} !gzip [OR]
RewriteCond %{HTTP_USER_AGENT} Konqueror
RewriteRule ^(.*)\.css$ $1_css.nozip [L]Соответственно, например main.css у нас изначально лежит в виде архива, а main_css.nozip — это обычная версия файла.
Если эти строки лежат в .htaccess в отдельной папке, то никак не влияют на файлы вне этой папки, так что в таком виде этот прием только полезен. При минимальных действиях на сервере получается то, что должно получаться.
Вот, наверное, все, если я чего-нибудь не запамятовал.
UPD1: Все-таки запамятовал. После вырезания всех лишних символов из HTML-выдачи отдается она в gzip'ованом виде с коэффициентом сжатия 9.