В ряде случаев фрагменты CSS- и JS-кода, а также изображения можно подставлять напрямую в HTML-документ.
Плюсы такой подстановки очевидны: количество запросов внешних объектов при загрузке страницы уменьшается до минимального количества. Минусом при использовании такого подхода на всех страницах сайта будет то, что пользователь лишится возможности кэшировать какие-либо объекты, вновь и вновь будет загружать их при просмотре страниц сайта.
Из этого очевидно, что подстановку внешних объектов в HTML-документ следует производить в следующих случаях:
Следуя приведенным выше рекомендациям, необходимо избегать встраивания CSS- и JS-кода непосредственно в теги веб-страницы (т. е. в атрибуты style, onclick и т. д.). Это исключит дублирование кода на странице, а также упростит его сопровождение.
Встраивать изображения прямо в HTML-документ можно, используя схему data:URI. По стандарту RFC 2397 такие URI предназначены для вставки небольших объектов как "непосредственных данных". Синтаксис должен быть следующим:
data:[<тип данных>][;base64],<данные>
В случае изображений необходимо указание mime-типа для них (например, image/gif). После него должно располагаться base64-представ-ление бинарного файла с изображением. Ниже приведен пример такой подстановки:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQA QMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDr Az3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkS uQmCC" width="16" height="14" alt="Встроенное изображение" />
Такие изображения, внедренные в HTML-страницы, разумеется, кэ-шируются только вместе с самим HTML-документом, содержащим их. Однако учитывая то, что изображения могут быть встроены и в файлы каскадных стилей, можно добиться кэширования этих изображений путем объединения их в одном внешнем CSS-файле.
У данного подхода есть следующие минусы:
Решение первой проблемы возможно за счет использования gzip-сжатия файлов CSS, в которых располагаются встроенные изображения. Вторая и третья проблемы легко решаются автоматическим преобразованием изображений в base64-представления при помощи серверных скриптов и созданием альтернативной версии кода для указанных браузеров Internet Explorer.
Описание способа автоматического встраивания изображений в код по схеме data:URI можно найти в "Уменьшение количества запросов" .
Перед тем как браузер сможет установить соединение с вебсервером, он должен разрешить доменное имя, т. е., зная его, вычислить IP-адрес сервера. Результат может быть закэширован в браузере и операционной системе пользователя, и задержки при повторном открытии веб-страницы не возникнет.
Если же такой записи в кэше не существует, задержка на время поиска IP-адреса может оказаться значительной и будет зависеть от доступности DNS-сервера, содержащего требуемую информацию (а иногда и от доступности цепочки таких серверов).
Наилучший способ уменьшить временные издержки, связанные с разрешением доменного имени — использовать наименьшее количество различных хостов для размещения внешних объектов веб-страниц, в особенности для тех объектов, которые требуются для первоначального отображения страницы.
Идеальным с точки зрения минимизации времени разрешения адреса DNS-сервера считается вариант, когда все объекты расположены на том же хосте, откуда была загружена веб-страница. Чем меньше используется хостов, тем больше вероятность того, что браузер сможет повторно использовать уже установленное соединение.
На практике же почти у всех браузеров существуют ограничения на количество одновременных соединений с одним хостом. Принимая во внимание это ограничение, наибольший выигрыш в скорости загрузки страниц можно получить, распределив загружаемые объекты по нескольким (4-6) хостам. Подробнее об особенностях параллельной загрузки объектов можно прочитать в пятой главе книги "Разгони свой сайт".
Иногда возникает необходимость перенаправить браузер с одного адреса на другой. Причины чаще всего следующие:
Какой бы ни была причина, каждый редирект порождает дополнительный HTTP-запрос, занимающий определенное время. Поэтому для страниц, для которых скорость загрузки наиболее критична, число реди-ректов должно быть сведено к минимуму. Для этого необходимо:
Браузеры и прокси-серверы обычно стремятся сохранить максимум информации в своих хранилищах, для того чтобы ускорить повторную загрузку ранее загруженных объектов. Важно помнить, что при этом возможна потеря актуальности представляемых данных, поэтому политика кэширования должна быть организована с учетом всех возможных ситуаций.
Кэширование — это один из наиболее мощных механизмов для уменьшения объема передаваемых по сети данных, притом внедряется этот механизм очень просто. Ниже приведено краткое описание наиболее значимых для кэширования заголовков.
Когда HTTP-сервер отправляет объект (например, HTML-документ или изображение) браузеру, он может дополнительно с ответом отправить заголовок Expires с меткой времени. Браузеры обычно хранят ресурс вместе с информацией об истечении его срока действия в локальном кэше. При последующих запросах к тому же объекту браузер сравнивает текущее время и метку времени у находящегося в кэше ресурса. Если метка времени указывает на дату в будущем, браузер загружает ресурс из кэша, не запрашивая его с сервера. Формат должен быть строго следующим:
день недели(сокр.), число(2 цифры) месяц(сокр.) год часы:минуты:секунды GMT
Заголовок Expires устанавливает время актуальности информации. Для ресурсов, которые не должны кэшироваться, его нужно выставлять в текущие время и дату (документ устаревает сразу же после получения), для форсирования кэширования его можно определять на достаточно далекую дату в будущем, например:
Expires: Mon, 27 Dec 2027 00:00:00 GMT
Заголовок Cache-Control определяет набор директив, относящихся непосредственно ко времени и специфике кэширования документа. Для запрета кэширования можно выставить его в следующее значение:
Cache-Control: no-store, no-cache, must-revalidate
Если же, наоборот, требуется сохранить ресурс в кэш браузера на продолжительный период времени, например, на год (60 * 60 * 24 * 365 секунд), нужно отправлять следующий заголовок:
Cache-Control: max-age=31536000
Заголовок Last-Modified может отправляться сервером для того, чтобы передать браузеру информацию о дате последнего изменения документа. Дата должна задаваться в том же формате, что и в случае с заголовком Expires:
Last-Modified: Tue, 4 Aug 1995 04:58:08 GMT
При наличии такой информации в локальном кэше браузер может в следующем запросе отправить ее в заголовке If-Modified-Since:
If-Modified-Since: Tue, 29 Oct 1994 19:43:31 GMT
В случае если дата последнего изменения осталась прежней, сервер ответит кодом состояния 304 Not Modified и данные не будут отправлены повторно. В противном случае сервер передаст новую версию файла.
Данная схема позволяет экономить время, затрачиваемое на передачу данных, однако при ее использовании браузер все равно будет устанавливать соединение с сервером, чтобы узнать, имеется ли более новая версия.
Заголовок ETag является почти полной аналогией заголовка Last-Modified за тем исключением, что в качестве передаваемого значения может выступать произвольная строка. Заголовок отправляется сервером в следующем формате:
ETag: "any-type-of-tag-or-hash"
Впоследствии, для того чтобы сервер мог определить, является ли объект, находящийся в кэше браузера, точно таким же, как соответствующий объект на сервере, браузер может отправить следующий заголовок:
If-None-Match: "any-type-of-tag-or-hash"
И аналогично, если теги совпадают, сервер отвечает кодом состояния 304 Not Modified и данные не передаются повторно. В противном случае сервер передаст новую версию файла.
Если время кэширования при помощи заголовков Expires и Cache-Control установлено на несколько лет вперед и требуется сообщить клиентскомубраузеру, что исходный объект изменился, можно воспользоваться двумя способами.
Можно обновить GET-строку запроса, например, используя номер версии или дату последнего изменения:
http://testdomain.com/global.css?v1
http://testdomain.com/global.css?20080901
А можно добавить номер версии или дату последнего изменения в само имя файла:
http://testdomain.com/global.v1.css
Во втором случае, для того чтобы исключить проблемы с локальными прокси-серверами, которые могут кэшировать файлы с GET-параметрами, и чтобы не создавать множество физических файлов, достаточно указать в конфигурации сервера правило: при запросах такого вида отдается каждый раз один и тот же файл.
В спецификации RFC-2616 HTTP-кэшированию посвящена целая глава. В ней подробно рассматривается, как работают все приведенные выше заголовки. Также о многих тонкостях использования кэширования более подробно рассказано в "Уменьшение количества запросов" .