Last-Modified и ETag

Давайте рассмотрим, какие существуют альтернативы прямому ограничению повторных загрузок ресурсов со стороны сервера и сохранению их в пользовательском кэше.

Last-Modified

Дополнительно к заголовку Cache-Control, который предупреждает браузер, что последний может не запрашивать исходный документ с сервера некоторое время, будет полезно проверять версию ресурса каждый раз при запросе. Например, нам нужно, чтобы браузер пользователя проверял файлы стилей не реже, чем раз в день, но при этом сами файлы могут меняться достаточно редко (например, несколько раз в месяц). Для решения такой задачи и была придумана пара заголовков Last-Modified и If-Modified-Since.

Как это работает? Дополнительно к периоду кэширования сервер может также отправить заголовок Last-Modified, который будет обозначать время последнего изменения файла на сервере. Если у браузера есть уже такой файл в локальном кэше, то он может отправить на сервер If-Modified-Since с соответствующим временем. В том случае, если файл не менялся со времени последнего посещения, то сервер ответит статус-кодом 304 и не будет пересылать содержимое файла.

Данная схема позволяет экономить время на передачу данных, однако, при ее использовании браузер все равно будет устанавливать соединение с сервером, чтобы узнать, имеется ли более новая версия.

ETag

ETag (англ. Entity Tags — тэги сущностей) — механизм, который используют браузеры и веб-серверы, чтобы определить, является ли объект, находящийся в кэше браузера, таким же, как соответствующий объект на сервере. Тэги сущностей являются почти полной аналогией Last-Modified заголовка за исключением того, что в качестве тэга может быть передана произвольная строка. Сервер указывает ETag для компонента, используя HTTP- заголовок ETag:

HTTP/1.1 200 OK
Last-Modified: Tue, 12 Dec 2008 03:03:59 GMT
ETag: «10c24bc-4ab-457e1c1f»
Content-Length: 19145

Позднее, если браузер хочет определить актуальность компонента, он передает заголовок If-None-Match для передачи ETag обратно на сервер. Если ETag совпадают, ответ от сервера приходит со статус-кодом 304, уменьшая, таким образом, объем передачи на 19145 байтов:

GET /b.png HTTP/1.1
Host: i.webo.in
If-Modified-Since: Tue, 12 Dec 2008 03:03:59 GMT
If-None-Match: «10c24bc-4ab-457e1c1f»
HTTP/1.1 304 Not Modified

Включить ETag для Apache можно, например, следующей директивой в конфигурации:

FileETag MTime Size

При этом ETag будет сформирован из даты изменения файла и его размера.

Синхронизация ETag и Last-Modified

Проблема ETag состоит в том, что обычно они используют атрибуты, специфичные в пределах одного сервера. ETag не совпадут, если браузер загрузит компонент страницы с одного сервера и попробует проверить его с другим сервером (у которого время изменения файла и(ли) номер блока на жестком диске для данного файла отличаются от первого) — ситуация очень распространенная, если вы используете кластер для обработки запросов. По умолчанию и Apache, и IIS включают в ETag такие данные, которые вряд ли дадут положительный результат при проверке на актуальность компонента на разных серверах.

Apache 1.3 и 2 генерирует ETag в формате inode-size-timestamp. Даже если один и тот же файл на разных серверах лежит в одной и той же папке, имеет те же права, размер и время, номер его иногда будет отличаться от сервера к серверу.

IIS 5.0 и 6.0 имеют похожий формат ETag: Filetimestamp:ChangeNumber. ChangeNumber — внутренняя переменная IIS для отслеживания изменений в конфигурации самого IIS, и нет гарантии, что эта переменная будет одинакова на всех серверах, обслуживающих веб-сайт.

В результате ETag, которые сгенерирует Apache или IIS для одного и того же файла, будут отличаться на разных серверах. Если ETag не будут совпадать, пользователь не будет получать маленького и быстрого ответа со статус-кодом 304 — собственно, ради чего ETag и разрабатывался. Взамен он будет получать стандартный код ответа 200 и далее весь запрошенный компонент.

Если сайт находится только на одном сервере, это не будет большой проблемой. Но если вы используете несколько серверов с Apache или IIS, устанавливающие ETag в соответствии с настройками по умолчанию, пользователи будут дольше загружать страницы, на серверах будет большая загрузка, нежели могла бы, вы будете тратить больше трафика, а прокси-серверы не будут кэшировать этот контент так, как хотелось бы. Даже если заголовок Expires будет установлен в далекое будущее, вам все равно будет приходить условный GET-запрос, когда пользователь перезагрузит страницу.

Если вы не получаете всех преимуществ, которые предоставляет ETag, тогда лучше совсем отключить его. Тэг Last-Modified позволяет проверять актуальность компонента на основании его времени изменения, а отключение ETag даст возможность уменьшить заголовки запроса и ответа. Если вы используете Apache, просто добавьте строку

FileETag none

в конфигурационный файл сервера.

Posted in Разгони свой сайт.