Ответ 1
Я отвечу на свой вопрос:
Статический общедоступный контент
Date: <current time>
Expires: <current time + one year>
Обоснование: это совместимо с проксими HTTP/1.0 и RFC 2616 Раздел 14: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21
Заголовок заголовка Last-Modified
не нужен для правильного кэширования (поскольку соответствующие пользовательские агенты следуют за заголовком Expires
), но могут быть включены для потребления конечного пользователя. Включение заголовка Last-Modified
также может уменьшить передачу данных сервера в случае, если пользователь нажмет кнопку "Обновить/Обновить" . Если заголовок Last-Modified
добавлен, он должен отражать реальные данные, а не что-то изобретенное. Если вы хотите уменьшить передачу данных на сервере (в случае, если пользователь нажимает кнопку "Обновить/Обновить" ) и не может включать реальный заголовок Last-Modified
, вы можете добавить заголовок ETag
, чтобы разрешить условное GET (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26). Если вы уже включили Last-Modified
, добавление ETag
- это просто отходы. Обратите внимание, что Last-Modified
явно превосходит, потому что он поддерживается клиентами HTTP и 1.0 и прокси. Подходящим значением для ETag
в случае динамических страниц является SHA-1 содержимого страницы/ресурса. Обратите внимание, что использование Last-Modified
или ETag
не поможет при загрузке сервера, только с исходящим интернет-каналом или скоростью передачи данных.
Статический непубличный контент
Date: <current time>
Expires: <current time>
Cache-Control: private, max-age=31536000, s-maxage=0
Vary: Cookie
Обоснование. Заголовки Date
и Expires
предназначены для совместимости с HTTP/1.0 и потому что нет разумного способа указать, что ответ является конфиденциальным, эти заголовки сообщают, что ответ может не кэшироваться. Заголовок Cache-Control
сообщает, что этот ответ может быть кэширован частным кешем, но общий кеш может не кэшировать ответ. s-maxage=0
добавлен, потому что private
может не поддерживаться всеми прокси-серверами, поддерживающими Cache-Control
(http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3 - у меня нет идея, какие прокси-серверы сломаны). Значение max-age
установлено в значение 60*60*24*365
(1 год), потому что спецификация HTTP/1.1 не определяет верхний предел для этого параметра, я полагаю, что это зависит от реализации. Заголовкам Expires
ДОЛЖНЫ быть ограничены одним годом в будущем, поэтому использовать ту же логику здесь должно быть хорошо. Заголовок Vary: Cookie
требуется, потому что сеанс, который используется для проверки того, разрешено ли посетителю видеть содержимое, переносится в файл cookie; потому что возвращаемый ответ зависит от значения cookie, кэш может не использовать кешированный ответ, если заголовок cookie изменяется.
Я мог бы лично сломать последнюю часть. Не включая заголовок Vary: Cookie
, я могу улучшить кеширование. Например: у меня есть образ профиля в http://domain.com/icon/12
, который возвращается только для выбранных аутентифицированных пользователей. У меня есть посетитель X
с идентификатором сеанса 5f2
, и я разрешаю изображение этому пользователю. Посетитель X
выходит из системы, а затем снова регистрируется. Теперь X
имеет идентификатор сеанса 2e8
, хранящийся в его cookie сеанса. Если у меня есть Vary: Cookie
, пользовательский агент X
не может использовать кэшированное изображение и вынужден перезагрузить его в свой кеш. Поскольку содержимое зависит от Cookie, условное GET с последним временем модификации не может быть использовано. Я не тестировал, если использование ETag
может помочь в этом случае, потому что в этом случае ответ сервера будет таким же (сопоставьте SHA-1 ETag
, вычисленный из содержимого ответа). Будьте предупреждены, что Internet Explorer (по крайней мере, до версии 9) всегда создает условный GET для ресурсов, которые включают Vary: Cookie
(источник: http://blogs.msdn.com/b/ie/archive/2010/07/14/caching-improvements-in-internet-explorer-9.aspx). Это связано с тем, что реализация внутреннего кэша MSIE не помнит, какой Cookie он отправил в первый раз, поэтому он не может знать, является ли текущий Cookie тем же самым.
Однако здесь приведен пример проблемы, вызванной сбросом заголовка Vary: Cookie
, чтобы показать, почему это действительно требуется для технически правильного поведения. См. Пример выше и представьте, что после того, как X вышел из системы, посетитель Y входит в систему с одним и тем же пользовательским агентом (пользовательский агент, возможно, был перезапущен между X и Y, это не имеет значения). Если Y просматривает страницу, содержащую ссылку на http://domain.com/icon/12
, тогда Y будет видеть значок, встроенный внутри страницы, даже если Y не сможет увидеть значок, если X ранее не использовал один и тот же пользовательский агент. В моем случае я не считаю это достаточно большой проблемой, потому что Y сможет получить доступ к значку вручную, проверив кеш пользовательского агента независимо от возможного добавления Vary: Cookie
. Однако эта проблема может помешать Y заметить, что он не имеет технически доступ к этому контенту (это может быть важно, например, если Y является соавтором контента). Если содержимое считается чувствительным, сервер должен отправить no-store
независимо от проблем, вызванных этой директивой Cache-Control
.
Здесь также добавление заголовка Last-Modified
поможет пользователям нажать кнопку "Обновить/Обновить" (см. обсуждение выше).
Неустойчивый публичный контент
Date: <current time>
Expires: <current time>
Cache-Control: public, max-age=0, s-maxage=0
Last-Modified: <real-last-modification-time>
Обоснование. Сообщите клиентам HTTP/1.0 и прокси, что этот ответ следует считать устаревшим немедленно. Время Last-Modified
включено, чтобы позволить пропускать передачу данных контента при повторном доступе к ресурсу, а клиент поддерживает условное GET. Если Last-Modified
не может использоваться, ETag
может использоваться как замена (см. Обсуждение выше). Крайне важно использовать Last-Modified
, чтобы разрешить условные GET с совместимыми с HTTP/1.0 клиентами.
Если содержимое может быть отложено еще немного, тогда Expires
, max-age
и s-maxage
[sic] следует соответствующим образом скорректировать. Например, добавление 5 секунд к этим может помочь много для очень популярного сайта, как это было предложено symcbean. Обратите внимание, что в отличие от условного GET, увеличение времени истечения приведет к уменьшению нагрузки на сервер вместо того, чтобы просто уменьшать трафик исходящих данных сервера (поскольку сервер будет видеть меньше запросов в целом).
Летучий непубличный контент
Date: <current time>
Expires: <current time>
Cache-Control: private, max-age=0, s-maxage=0
Last-Modified: <real-last-modification-time>
Vary: Cookie
Обоснование. Сообщите клиентам HTTP/1.0 и прокси, что этот ответ следует считать устаревшим немедленно. Время Last-Modified
включено, чтобы позволить пропускать передачу данных контента при повторном доступе к ресурсу, а клиент поддерживает условное GET. Если Last-Modified
не может использоваться, ETag
может использоваться как замена (см. Обсуждение выше). Крайне важно использовать Last-Modified
, чтобы разрешить условные GET с совместимыми с HTTP/1.0 клиентами. Также обратите внимание, что Cache-Control
не должен включать no-cache
, must-revalidate
или no-store
, потому что использование любой из этих директив приведет к поломке кнопки "Назад", по крайней мере, в одном пользовательском агенте. Однако, если контент, передаваемый сервером, содержит чувствительный материал, который не должен храниться в постоянном хранилище, флаг no-store
ДОЛЖЕН использоваться независимо от разрыва кнопки "Назад". Предупреждение: обратите внимание, что использование no-store
не может предотвратить попадание конфиденциального материала на жесткий диск без шифрования, если операционная система включена и обмен не зашифрован! Также обратите внимание, что использование no-store
имеет мало смысла, если соединение не зашифровано (HTTPS/SSL).