Я отвечу на свой вопрос:
Статическое общедоступное содержимое
Date: <current time>
Expires: <current time + one year>
Обоснование: Это совместимо с прокси HTTP / 1.0 и RFC 2616 Section14: 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
не поможет с нагрузкой на сервер, только с исходящим интернет-каналом / скоростью передачи данных на сервере.
Статический непубличныйcontent
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
iдобавлено потому, что 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).