Если Вы когда-нибудь занимались созданием динамического сайта, то есть сайта, состоящего не из статичных HTML страничек, а скриптов, взаимодействующих с разными файлами и базами данных, Вы наверняка сталкивались (а если нет, то еще столкнетесь) с такими проблемами: «правильное» кэширование; «правильные» HTTP заголовки.
Поясняю первый пункт. Кэширование — механизм, позволяющий клиенту (то есть пользователю на том конце соединения, точнее — его браузеру, для пользователя этот процесс незаметен) при просмотре одних и тех же файлов (например, картинок, составляющих элементы дизайна сайта, или файлов стилей CSS) не скачивать их каждый раз заново, а скачивать только однажды, а затем, по мере необходимости, использовать сохраненную на компьютере клиента копию. Принцип его работы примерно таков: при возникновении очередной необходимости скачать файл клиент обращается к серверу с запросом, не был ли файл изменен (не устарела ли копия на машине клиента), и если нет, не скачивает его заново, а использует сохраненный вариант. В браузерах, точно придерживающихся спецификации протокола HTTP, можно также добиться того, что запросы вообще не будут посылаться каждый раз, если есть сохраненная копия файла и точно известно, что она не успела устареть. Прелесть в том, что трафик (объем скачанных из Интернет данных) клиента уменьшается, и пользователь видит, что «сайт работает быстро». Естественно, уменьшается и трафик сервера, что позволяет снизить нагрузку на сервер и даже сэкономить, если Вы пользуетесь платным хостингом. Проблема состоит в том, что данный механизм для страниц динамического сайта сам собой работать не будет, его надо построить (тогда как для статичных страниц и картинок серверы обычно могут полностью автоматизировать процесс). Построение системы осуществления «правильного кэширования» описано далее, в разделах Теория и Практика. Поясню теперь пункт второй. Когда клиент запрашивает у сервера файл по протоколу HTTP, он, кроме содержимого самого файла (код в случае HTML файла, текст в случае текстового файла и т.п.), получает также HTTP headers — заголовки HTTP. Это служебные текстовые поля с информацией, которая не отображается в браузере, но интерпретируется им и, в основном, служит для сообщения клиенту данных о запрашиваемой странице. Заголовок ETag («объектная метка»), например, служит для присвоения каждой странице уникального идентификатора, который остается неизменным, пока страница не модифицирована, и изменяется, если изменились данные на странице. Этот заголовок сохраняется на клиенте, и в случае необходимости повторного скачивания «меченой» страницы позволяет браузеру обращаться к серверу с запросом 'If-None-Match' — в таком случае сервер должен по значению ETag-метки сохраненной на клиенте копии определить, не устарела ли она, и если нет, ответить кодом '304 Not Modified' («не модифицировано»), и страница не будет скачена еще раз. Заголовок Last-Modified («последнее изменение») предназначен для того, чтобы сообщить клиенту дату и время, когда последний раз изменилась запрашиваемая страница. Используя его, клиент, подобно случаю с ETag, может обращаться к серверу с запросом 'If-Modified-Since' — в этом случае сервер должен сравнить дату последней модификации копии, сохраненной на клиенте, с актуальной датой последней модификации. Если они совпадут, это значит, что копия в кэше клиента не устарела, и повторное скачивание не нужно (код ответа '304 Not Modified'). Last-Modified также необходим для корректной обработки Вашего сайта роботами - спайдерами (спайдер, англ. «паук» — это робот, который ходит по паутине Интернета и индексирует сайты, чтобы их можно было найти через поисковые системы, например, Google), которые используют информацию о дате модификации страниц в целях сортировки результатов поиска по дате, а также для определения частоты обновляемости Вашего сайта (см. например, что об этом пишет Яndex). Какой из этих методов определения «свежести» интернет-страниц использует клиент (и использует ли он их вообще), зависит от его возможностей и настроек. По хорошему, надо отправлять оба этих заголовка с каждым файлом, отданным Вашим сервером. Есть еще заголовок Expires («истечение») — он сообщает браузеру, какой временной промежуток можно считать, что копия страницы в кэше свежа, и вообще не обращаться к серверу с запросами. Это удобно для таких файлов, о которых вы точно знаете, что они не изменятся ближайший час/день/месяц: фоновая картинка страницы, например. К сожалению, поддерживается не всеми браузерами. В рассматриваемом примере Expires будет равен десяти минутам, что подходит для большинства сайтов, на которых информация обновяется не слишком часто (~ раз в час). Чтобы реализовать отправку «правильных» HTTP заголовков страницами Вашего сайта, надо как-то определять, когда модифицируются эти страницы. Проблема состоит в том, что в отличие от ситуации со статичными HTML файлами, когда дата модификации файла и его содержимого это одно и тоже, динамические страницы могут менять свое содержимое в зависимости от предусмотренных разработчиком внешних факторов (время суток, запрос пользователя, импорт данных из БД) без изменения файла скрипта. То есть дата модификации файла и информации, которую он отсылает клиенту, запросто могут не совпадать. Другая проблема, вытекающая из предыдущей, заключается в том, что часто на динамических сайтах на каждую страницу ставят голосование, "шутку дня" или баннерокрутилку, код которых меняется при каждой следующей загрузке. То есть надо смотреть не на всю сгенерированную страницу, а только на ту ее часть, которая несет основную информацию — текст статьи, прайс-лист и т.п. На первый взгляд все очень сложно и непонятно, но пугаться не стоит, потому как система, которая будет рассмотрена далее, достаточно проста. Сложнее понять то, что нам нужно сделать, чем то, как. Для решения вышеописанных проблем необходимо: "Отловить" со страницы ту часть контента, за которой мы "следим"; Сравнить то, что получилось, с тем, что получилось в прошлый раз — для этого использовать БД, где и хранить информацию о страницах; В случае модификации данных — обновить информацию о странице в БД; Отослать клиенту HTTP заголовки в зависимости от его запроса.
Сделать это можно разными способами. Мы будем рассматривать систему, написанную на языке PHP, так как этот язык сейчас популярен, довольно прост для понимания и поддерживается большинством хостингов, в том числе и бесплатными. Данные мы будем хранить в БД MySQL по тем же причинам. Итак, что там у нас там, на сайте? Динамические страницы, то есть PHP скрипты. Как функционирует эта «динамика»? Если сайт у Вас небольшой, то, скорее всего, у Вас под каждую страницу существует свой скрипт: index.php – для главной страницы, news.php для страницы новостей и т.п. Если же сайт у Вас выходит за рамки «домашней странички» и имеет сложную структуру, свой форум или пользовательскую зону, построен с использованием баз данных, то, вероятно, одним скриптом типа showpage.php генерируются сотни концептуально различных страниц (например, страницы форума генерирует один скрипт, но страницы-то разные, и надо следить за каждой отдельно). Первый случай проще для рассмотрения, хотя, если Вы поймете суть предлагаемой системы, Вы сможете без особых проблем интегрировать ее и на сайте, описанном во втором случае. А мы рассмотрим случай первый. Чего надо «избежать» при «отлове» контента? Баннеров, счетчиков и всего, что написано в меню. Это не принципиально — Вы сами решаете, какой объем информации, отдаваемой Вашими скриптами, будет использоваться для определения их модификации. Если Ваш сайт слишком громоздкий и сложный для такой модификации, есть более простой выход: буферизация вывода, стандартная функция PHP (Когда буферизация вывода активна, все, что генерирует скрипт, не высылается клиенту, а сохраняется во внутреннем буфере.) То, что попало в буфер, можно положить в переменную и работать с этими данными, как с обычной строковой переменной, а потом отослать клиенту. Тогда Вам необходимо просто найти в коде начало и конец того куска выводимой информации, которую надо проверять, и маркировать этот кусок HTML-комментариями. Теперь мы отделили «мух от котлет» и информация, которую будем «контент-мониторить», заключена у нас между HTML-комментариями. Остается включить буферизацию, в конце скрипта взять данные из буфера, выловить оттуда часть кода между комментариями, и обработать его на предмет модификации. По результатам этой обработки, а также в зависимости от запроса клиента, отослать HTTP заголовки.
|