Для начала давайте попробуем определиться с тем, что подразумевается под «динамическим сайтом». Динамика, как известно, означает изменение.
То есть если мы, скажем, раз в месяц заменяем какую-то html-страничку на сайте, то он, в принципе, может считаться динамическим... Но понятно, что имеется в виду нечто совсем другое, а именно ситуация, когда страница выводится каким-то скриптом. При этом, даже если содержимое этой выводимой странички не будет меняться, то сайт все равно будет называться «динамическим». Занятно, не правда ли?
С точки зрения сервера динамический сайт отличается тем, что сервер не может определить дату последней модификации документов, время их жизни и некоторые другие параметры. Соответственно, при «разговоре» веб-сервера с кеширующим прокси возникают сложности с тем, можно ли кешировать полученный документ. Так как никто (кроме веб-мастера) этого точно не знает, то сервер обычно старается сделать так, чтобы документ не кешировался — а именно выставляет всяческие страшные ограничения в HTTP-заголовках. Понятно, что это приводит нас к ситуации, когда мы не используем преимущества кеширования, а следовательно — увеличивается нагрузка на сервер, увеличиваются загрузка каналов и время получения страниц пользователем...
Но случаи «полной динамичности» сайтов — когда выдаваемая страница уникальна для каждого запроса — достаточно редки. Значительно чаще страницы повторяются, по крайней мере, в течение более или менее длительного времени (здесь мы не рассматриваем встраивание ротируемой рекламы). А раз содержимое страниц на протяжении какого-то интервала времени остается неизменным, значит, есть смысл попытаться их кешировать.
В заметке «Кешируем свой сайт» говорилось, что определением параметров кеширования статичных файлов занимается веб-сервер. Поэтому, если мы не хотим мучиться с настройками скриптов, то самым простым способом обеспечения кеширования динамического сайта будет сохранение сгенерированных страниц в виде банальных html-файлов. В некоторых случаях это может оказаться очень удобным решением — например, для сайта с большим количеством статей, на котором эти статьи еще и регулярно добавляются. Сами статьи не меняются (за очень редким исключением), а навигационные страницы можно перегенерировать каждый раз при добавлении новой статьи. Одно из важных условий при использовании подобной схемы заключается в том, чтобы не генерировать весь сайт заново при каждом изменении, а заменять только те файлы, которые реально обновились — иначе сервер изменит заголовок Last-Modified для всех файлов, и посетителям придется качать их заново.
Если же этот способ вам не подходит, то придется модифицировать скрипты. Для начала присмотритесь к своему сайту и определите, какие страницы могут быть скешированы и на какое время. Отдельно определите те страницы, которые кешироваться не должны — как правило, это различные «редакторские» страницы и страницы с текущей статистикой.
Обратите внимание на следующие моменты:
Скрипты, использующие POST, в большинстве случаев не кешируются. По возможности, используйте GET: кеширующие прокси ориентируются на URL документа. POST имеет смысл использовать только тогда, когда объем данных достаточно велик. Например, в поисковых запросах GET вполне применим, а если вы проанализируете эти запросы, то наверняка обнаружите, что множество из них повторяются весьма регулярно. К счастью, переделать скрипты с POST на GET совсем не сложно.
Еще более правильным решением будет использовать для передачи данных адрес, поскольку некоторые прокси отказываются кешировать страницы, в адресе которых используется знак вопроса. Эта рекомендация вряд ли применима к поиску, но вполне успешно может работать, скажем, при выводе статей — просто вместо адреса /redir.php?url=www.myhost.ru%2Farticle.cgi%3Fid%3D14 появится что-то вроде /redir.php?url=www.myhost.ru%2Farticle%2F14%2F. Реализовать такой метод можно самыми разными способами — начиная с использования mod_rewrite и заканчивая написанием специального скрипта, который будет вызываться при возникновении 404-й ошибки.
Следующая ловушка связана с cookies. Если ваш скрипт устанавливает «куку», то большинство прокси откажутся его кешировать. Поэтому стоит подумать о том, действительно ли вам требуется устанавливать cookie при каждом обращении — в абсолютном большинстве случаев этого можно избежать.
При использовании Apache и mod_deflate вы столкнетесь с еще одной сложностью: во-первых, для сжатых страниц не генерируется Content-Length, а во-вторых, по умолчанию mod_deflate не сжимает страницы, запрашиваемые прокси (что снижает эффетивность кеширования как для сервера — несжатые страницы забирают больше трафика, — так и для пользователя — увеличивается время на получение страницы от прокси). Можно установить директиву DeflateProxied в положение ON, но тогда есть риск, что какой-то пользователь, использующий старый браузер, получит от прокси сжатую страницу и не сможет ее увидеть. Впрочем, процент таких пользователей весьма невелик и постепенно снижается, так что, пожалуй, им можно и пренебречь. Подробности о настройке mod_deflate можно почитать в документации
Теперь пора прописывать заголовки. В зависимости от языка, на котором вы пишете свои скрипты, для этого могут использоваться разные функции — например, в PHP есть специальная функция header(), а в Perl можно написать, скажем, такое:
#!/usr/bin/perl
print "Content-type: text/html\n";
print "Expires: Thu, 08 May 2003 08:37:25 GMT\n";
print "\n";
Главное — не забыть, что заголовки должны быть выданы до того, как начнется вывод самого документа.
Для начала «обработаем» скрипты, которые кешироваться не должны. Так как «некешируемые» страницы чаще всего нужны для использования в защищенных областях — например, в панели администрирования — то проще всего использовать SSL для таких соединений. SSL-страницы не кешируются и не расшифровываются прокси-серверами, поэтому ваши данные не станут достоянием гласности. Если же использовать SSL по каким-то причинам не хочется, то для начала сделайте ввод пароля и прочей информации через POST. Кроме того, установите в заголовках Last-Modified на текущее время (не забудьте, что должно указываться не местное время, а по Гринвичу).
Last-Modified: Thu, 08 May 2003 08:37:25 GMT
Expires: 0
Cache-Control: no-cache, no-store, must-revalidate
Многие руководства рекомендуют устанавливать Expires на какую-то дату в прошлом (и в RFC написано, что так делать можно), но, как показала практика, многие кеширующие прокси считают такое значение неверным и отбрасывают его (несмотря на то, что все в том же RFC2616 сказано, что неправильный формат заголовка Expires должен запрещать кеширование). А отбросив Expires и не видя других указаний, такие прокси используют свои настройки по умолчанию для кеширования документа. Именно поэтому для запрета кешиования лучше указывать Expires: 0 или указывать дату, скажем, на одну секунду вперед от времени запроса.
В качестве дополнительной страховки от кеширования можно, например, вызывать скрипт, указывая в GET запросе какой-то постоянно изменяющийся параметр — проще всего для этого использовать текущее время. Такую ссылку можно генерировать либо скриптом на сервере, либо, что правильнее, используя JavaScript. В последнем случае ссылка будет содержать разные URL даже в том случае, если посетитель сохранит страницу у себя на компьютере.
Ну, и еще стоит воспользоваться META-тегами, о которых шел разговор в предыдущей заметке.
Теперь займемся остальными скриптами. Как правило, дата последнего изменения содержимого страницы скрипту известна — например, в случае списка статей можно запросить у базы данны дату добавленения последней статьи и указать ее в качестве Last-Modified. Среднее время обновления страниц можно либо вычислять тем же скриптом, либо просто определить «на глазок» и жестко прописать в скрипте. Скажем, уже опубликованная статья вряд ли будет меняться чаще, чем раз в месяц, а список статей — раз в сутки. Исходя из этих данных генерируем заголовок Expires — просто прибавляем к текущему времени время жизни страницы и все.
По большому счету, на этом можно и закончить. Но можно и немножко продолжить, воздав должное появившимся в HTTP 1.1 функциям управления кешированием. Скажем, указать:
Cache-Control: public, max-age=86400, must-revalidate
Вообще, заголовок Cache-Control дает довольно широкие возможности по управлению кешированием — например, там есть возможность запретить кеширование только каких-то определенных полей, но, к сожалению, стандарт этот поддерживается далеко не всеми прокси. Однако если вы хотите, чтобы ваши скрипты были максимально эффективны, то стоит предусмотреть использование этого заголовка, поскольку число прокси-серверов, его понимающих, будет увеличиваться. Кстати, в своих скриптах стоит встроить разбор запроса — как минимум, «выкусывать» запрос "If-Modified-Since" и, если данные с того времени не изменились, выдавать в ответ код 304. Также можно еще прописать Expires в META-теге, правда, вряд ли это даст какой-либо дополнительный выигрыш.
В следующей заметке мы поговорим о том, как, сохранив преимущества кеширования, постараться избавиться от его недостатков...
Ссылки по теме
Статья получена: hostinfo.ru