Подтвердить что ты не робот

Заголовки HTTP: управление механизмом кэширования и истории

Я пытаюсь найти лучшие HTTP-заголовки для отправки в четырех случаях использования. Я надеюсь получить заголовки, которые не зависят от версии агента пользователя/протокола, но я соглашусь, если ничего другого не подойдет. Все URL-адреса получаются с помощью полностью настраиваемого обработчика, поэтому я могу выбрать все заголовки, как мне нравится, это все о промежуточных прокси и пользовательских агентах. Если это возможно, это должно быть совместимо с клиентами HTTP/1.0 и HTTP/1.1. Если существует несколько решений, лучший из них будет самым коротким при отправке по проводу.

Статический общедоступный контент

Все "Статический общедоступный контент" - это то, о чем HTTP-адрес действительно: если URL-адрес тот же, контент тот же. Я могу сделать это легко: например, я поместил значок профиля пользователя в http://domain.com/profiles/xyz/icon/1234abcd, где "1234abcd" - это SHA-1 содержимого файла иконы. Если в будущем я перейду к значку, я создам новый URL-адрес и изменю все существующие источники, которые должны использовать новый значок. Каковы наилучшие заголовки, чтобы заявить, что это может быть кэшировано навсегда и может быть разделено? Я сейчас что-то думаю по строкам:

Date: <current time>
Expires: <current time + one year>

Достаточно ли этого, чтобы разрешить кеширование агентами и прокси-серверами? Нужно ли мне Last-Modified или Pragma?

Статический непубличный контент

Все "Статический непубличный контент" - это материал, который статичен, но может быть недоступен для всех. Фактически, этот контент будет доступен только для выбранных зарегистрированных пользователей (сеанс хранится с сеансом UUID сессии cookie сеанса). Если URL-адрес один и тот же, контент один и тот же. Однако ответ не является общедоступным. Вариант использования может быть изображением, совместно используемым избранными друзьями в службе социальной сети. Я сейчас что-то думаю по строкам:

Date: <current time>
Expires: <current time>
Cache-Control: private, max-age=<huge number>, s-maxage=0

Достаточно ли этого, чтобы разрешить кеширование агентами пользователя и отключить прокси? Мне нужно Pragma?

Неустойчивый публичный контент

Все "Неустойчивое публичное содержимое" - это материал, который нестабилен и доступен для всех. Что-то вроде frontpage http://slashdot.org/, когда вы не вошли в систему. Цель состоит в том, чтобы быстро обновлять контент в неизменяемом URL. Обратите внимание, что я НЕ хочу разрушать механизм истории пользовательских агентов (то есть щелкнуть что-то с измененной страницы, а затем нажать кнопку "Назад" , не приведет к извлечению изменчивой страницы с сервера), однако, щелкнув ссылку, которая идет на на первой странице должен быть выбран ресурс с сервера). Я сейчас что-то думаю по строкам:

Date: <current time>
Expires: <current time>
Cache-Control: public, max-age=0, s-maxage=0

Достаточно ли этого, чтобы предотвратить кеширование, но разрешить механизм истории (кнопка возврата)? Я знаю, что если я отправлю Cache-Control: no-store, must-revalidate, я могу принудительно перезагрузить, но это не то, что я хочу, потому что это тоже сломает кнопку "Назад" . Нужно ли мне Last-Modified или Pragma?

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

Летучий непубличный контент

Все "Неустойчивый непубличный контент" - это материал, который неустойчив и недоступен для всех (частный). Что-то вроде главной страницы http://slashdot.org/, когда вы вошли в систему. Цель состоит в том, чтобы быстро обновлять контент в неизменяемом URL. Обратите внимание, что я НЕ хочу разрушать механизм истории пользовательских агентов (то есть щелкнуть что-то с измененной страницы, а затем нажать кнопку "Назад" , не приведет к извлечению изменчивой страницы с сервера), однако, щелкнув ссылку, которая идет на на первой странице должен быть выбран ресурс с сервера). Я сейчас что-то думаю по строкам:

Date: <current time>
Expires: <current time>
Cache-Control: private, max-age=0, s-maxage=0

Достаточно ли этого, чтобы предотвратить кеширование, но разрешить механизм истории (кнопка возврата)? Мне нужно Pragma?


Вещи, которые все еще нуждаются в тестировании с моими предлагаемыми заголовками:

  • Убедитесь, что личный контент не будет пропущен через прокси HTTP/1.0.
  • Убедитесь, что кеширование работает правильно в прокси.
  • Убедитесь, что кеширование работает правильно в пользовательских агентах.
  • Убедитесь, что механизм агентов пользовательского агента работает в пользовательских агентах (все случаи).
  • Убедитесь, что после ссылки на энергозависимую страницу выбирается свежий контент с сервера.
  • Проверьте все результаты при использовании HTTPS вместо HTTP.
4b9b3361

Ответ 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).

Ответ 2

В основном ОК, однако вам нужно помнить, что прокси-серверы HTTP/1.0 могут кэшировать содержимое, поданное как

Cache-Control: private

Итак, вы должны установить явный заголовок с датой, а также заголовок expires.

Для вашего "Статического непубличного контента" вы должны добавить заголовок "Varies: Cookie".

Для вашего "Неуловимого публичного контента": насколько быстро он меняется? Установка TTL +5 секунд может выгрузить много усилий с ваших серверов.

Для "Неустойчивого непубличного контента" вы, вероятно, должны добавить no-cache, должны-revalidate в заголовок Cache-control.

Заголовки Pragma, выпущенные с сервера, не должны влиять на клиентов и прокси.

Проверите, что произойдет, когда истекает срок действия вашего кеша (IME вы можете получить систему, даже более медленную, чем один доступ без кэша, заполненный за счет всех условных запросов /304 ответов)