Ошибки и поведение кэша при неполном отклике
Кэш, который получает неполный отклик (например, с меньшим числом байт, чем специфицировано в заголовке ContentLength ), может его запомнить. Однако кэш должен воспринимать эти данные как частичный отклик. Результатом может быть полный или частичный отклик. Кэш не должен возвращать частичный отклик клиенту без явного указания на то, что он частичный, используя статусный код 206 (Partial Content). Кэш не должен возвращать частичный отклик, используя статусный код 200 (OK).
Если кэш получает отклик 5xx при попытке перепроверить запись, он может переадресовать этот отклик запрашивающему клиенту или действовать так, как если бы сервер не смог ответить на запрос. В последнем случае он может вернуть отклик, полученный ранее, если только запись в кэше не содержит директиву Cache-Control mustrevalidate.
Побочные эффекты методов GET и HEAD
Если исходный сервер напрямую не запрещает кэширование своих откликов, методы приложения GET и HEAD не должны давать каких-либо побочных эффектов, которые вызывали бы некорректное поведение, если эти отклики берутся из кэша. Они все же могут давать побочные эффекты, но кэш не обязан рассматривать такие побочные эффекты, принимая решение о кэшировании. Кэши контролируют лишь прямые указания исходного сервера о запрете кэширования.
Обратим внимание только на одно исключение из этого правила: некоторые приложения имеют традиционно используемые GET и HEAD с запросами URL, содержащими "?" в части rel_path. Кэши не должны обрабатывать отклики от таких URL как свежие, если только сервер не присылает непосредственно значение времени жизни. Это, в частности, означает, что отклики от серверов HTTP/1.0 для этих URI не следует брать из кэша.
Несоответствие после актуализации или стирания
Под воздействием определенных методов на исходный сервер одна или более записей, имеющихся в кэше, становятся неявно непригодными. То есть, они могут оставаться свежими, но не вполне точно отражать то, что исходный сервер пришлет в ответ на новый запрос.
В протоколе HTTP не существует способа гарантировать, что все такие записи в кэше будут помечены как непригодные. Например, запрос, который вызывает изменение в исходном сервере, не обязательно проходит через прокси, где в кэше хранится такая запись. Однако несколько правил помогает уменьшить вероятность некорректного поведения системы.
Выражение "пометить объект как непригодный" означает, что кэш должен либо удалить все записи, относящиеся к этому объекту, из памяти или должен пометить их как непригодные (invalid), что вызовет обязательную перепроверку пригодности перед отправкой в виде отклика на последующий запрос.
Некоторые методы HTTP могут сделать объект непригодным. Это объекты, на которые осуществляется ссылка либо через Request-URI, либо через заголовки отклика Location или Content-Location (если они имеются). Это методы:
PUT
DELETE
POST
Обязательная пропись (Write-Through Mandatory)
Все методы, которые предположительно могут вызвать модификацию ресурсов исходного сервера, должны быть прописаны в исходный сервер. В настоящее время сюда входят все методы, кроме GET и HEAD. Кэш не должен отвечать на такой запрос от клиента, прежде чем передаст запрос соответствующему серверу и получит отклик от него. Это не препятствует кэшу послать отклик 100 (Continue), прежде чем вовлеченный сервер ответит.
Альтернатива, известная как writeback или copyback кэширование, в HTTP/1.1 не допускается изза трудности обеспечения согласованных актуализаций и проблем, связанных с отказами сервера, кэша или сети до осуществления обратной записи (writeback).
Замещения в кэше
Если от ресурса получен новый кэшируемый отклик, в то время как какой-либо отклик для того же ресурса уже записан в кэш, кэшу следует использовать новый отклик для ответа на текущий запрос. Он может ввести его в память кэша и может, если он отвечает всем требованиям, использовать в качестве отклика для будущих запросов.
Замечание. Новый отклик, который имеет значение заголовка Date старше, чем кэшированные уже отклики, не должен заноситься в кэш.
Списки предыстории
Агенты пользователя часто имеют механизмы "исторического" управления, такие, как кнопки Back и списки предыстории, которые могут использоваться для повторного отображения объекта, извлеченного ранее в процессе сессии. Механизмы предыстории и кэширования различны. В частности, механизмы предыстории не должны пытаться показать семантически прозрачный вид текущего состояния ресурса. Скорее, механизм предыстории предназначен для того, чтобы в точности показать, что видел пользователь, когда ресурс был извлечен. По умолчанию время годности не приложимо к механизмам предыстории. Если объект все еще в памяти, механизм предыстории должен его отобразить, даже если время жизни объекта истекло и он объявлен непригодным, — если только пользователь не сконфигурировал агента так, чтобы обновлять объекты, срок годности которых истек. Это не запрещает механизму предыстории сообщать пользователю, что рассматриваемый им объект устарел.
Если механизмы предыстории излишне мешают пользователю просматривать устаревшие ресурсы, то это заставит разработчиков избегать пользоваться контролем времени жизни объектов. Разработчикам следует считать важным, чтобы пользователи не получали сообщений об ошибке или предупреждения, когда они пользуются навигационным управлением (например, таким, как клавиша BACK).
Определения полей заголовка
Этот раздел определяет синтаксис и семантику всех стандартных полей заголовков HTTP/1.1. Для полей заголовков объекта как отправитель, так и получатель могут рассматриваться клиентом или сервером, в зависимости от того, кто получает объект.
Поле Accept
Поле заголовка запроса Accept может применяться для спецификации определенных типов среды, которые приемлемы для данного ресурса. Заголовки Accept могут использоваться для индикации того, что запрос ограничен в рамках определенного набора типов, как в случае запросов отображения в текущей строке.
Accept = "Accept" ":"
#( mediarange [ acceptparams ] )
mediarange = ( "*/*"
| ( type "/" "*")
| ( type "/" subtype )
) *( ";" parameter )
acceptparams = ";" "q" "=" qvalue *( acceptextension )
acceptextension = ";" token [ "=" ( token | quotedstring ) ]
Символ звездочка "*" используется для того, чтобы группировать типы среды с "*/*", указывающим на все типы, и "type/*", указывающим на все субтипы данного типа. Группа сред может включать в себя параметры типа среды, которые применимы. За каждой группой сред может следовать один или более параметров (acceptparams), начинающихся с "q"параметра для указания фактора относительного качества. Первый "q" параметр (если таковой имеется) отделяет параметры группы сред от параметров приема. Факторы качества позволяют пользователю или агенту пользователя указать относительную степень предпочтения для данной группы сред, используя шкалу значений q от 0 до 1. Значение по умолчанию соответствует q=1.
Замечание. Использование имени параметра "q" для отделения параметров типа среды от параметров расширения Acceptсвязано с исторической практикой. Это мешает присвоению параметру типа среды имени "q".
Пример
Accept: audio/*; q=0.2, audio/basic.
должен интерпретироваться, как "Я предпочитаю audio/basic, но шлите мне любые типы аудио, если это лучшее, что имеется после 80% понижения качества". Если поле заголовка Accept отсутствует, тогда предполагается, что клиент воспринимает все типы среды. Если поле заголовка Accept присутствует и если сервер не может послать отклик, который является приемлемым, согласно комбинированному значению поля Accept, тогда сервер должен послать отклик 406 (not acceptable). Более сложный пример:
Accept: text/plain; q=0.5, text/html,
text/xdvi; q=0.8, text/xc
Это будет интерпретироваться следующим образом: text/html и text/xc являются предпочтительными типами сред, но, если их нет, тогда следует слать объект text/xdvi; если он отсутствует, следует присылать объект типа text/plain.
Группы сред могут быть заменены другими группами или некоторыми специальными типами среды. Если используется более одного типа среды, предпочтение отдается наиболее специфичному типу. Например:
Accept: text/*, text/html, text/html;level=1, /
имеет следующие предпочтения:
1. text/html;level=1
2. text/html
3. text/*
4. /
Фактор качества типа среды, ассоциированный с данным типом, определен путем нахождения группы сред с наивысшим предпочтением, который подходит для данного типа. Например,
Accept: text/*;q=0.3, text/html;q=0.7, text/html;level=1,
text/html;level=2;q=0.4, /;q=0.5
в результате будут установлены следующие величины:
text/html;level=1 = 1
text/html = 0.7
text/plain = 0.3
image/jpeg = 0.5
text/html;level=2 = 0.4
text/html;level=3; = 0.7
Агент пользователя может быть создан с набором значений качества по умолчанию для определенных групп среды. Однако, если только агент пользователя не является закрытой системой, которая не может взаимодействовать с другими агентами, этот набор по умолчанию должен конфигурироваться пользователем.
Поле Accept-Charset
Поле заголовка запроса Accept-Charset может быть использовано для указания того, какой символьный набор приемлем для отклика. Это поле позволяет клиентам, способным распознавать более обширные или специальные наборы символов, сигнализировать об этой возможности серверу, который способен представлять документы в рамках этих символьных наборов. Набор символов ISO-88591 может считаться приемлемым для всех агентов пользователя.
AcceptCharset = "Accept-Charset" ":"
1#( charset [ ";" "q" "=" qvalue ] )
Каждому символьному набору может быть поставлено в соответствие значение качества, которое характеризует степень предпочтения пользователя. Значение по умолчанию q=1. Например, Accept-Charset: ISO-88595, unicode11;q=0.8. Если заголовок Accept-Charset отсутствует, по умолчанию это означает, что приемлем любой символьный набор. Если заголовок Accept-Charset присутствует и если сервер не может послать отклик, который приемлем с точки зрения заголовка Accept-Charset, тогда он должен послать сообщение об ошибке со статусным кодом 406 (not acceptable), хотя допускается посылка и отклика unacceptable.
Поле Accept-Encoding
Поле заголовка запроса Accept-Encoding сходно с полем Accept, но регламентирует кодировку содержимого, которая приемлема в отклике.
Accept-Encoding = "Accept-Encoding" ":"
#( contentcoding )
Например, Accept-Encoding: compress, gzip. Если заголовок Accept-Encoding в запросе отсутствует, сервер может предполагать, что клиент воспримет любую кодировку информации. Если заголовок Accept-Encoding присутствует и если сервер не может послать отклик, приемлемый согласно этому заголовку, тогда серверу следует послать сообщение об ошибке со статусным кодом 406 (Not Acceptable). Пустое поле Accept-Encoding указывает на то, что не приемлемо никакое кодирование.
Поле Accept-Language
Поле заголовка запроса Accept-Language сходно с полем Accept, но регламентирует набор естественных языков, которые предпочтительны в отклике на запрос.
Accept-Language = "Accept-Language" ":"
1#( languagerange [ ";" "q" "=" qvalue ] )
languagerange = ( ( 1*8ALPHA *( "" 1*8ALPHA ) ) | "*" )
Каждому набору языков может быть поставлено в соответствие значение качества, которое представляет собой оценку предпочтений пользователя для языков, специфицированных в диапазоне. По умолчанию значение качества "q=1". Например,
Accept-Language: da, engb;q=0.8, en;q=0.7
будет означать: "Я предпочитаю датский, но восприму британский английский и другие типы английского". Список языков согласуется с языковой меткой, если он в точности равен метке или если он в точности равен префиксу метки, такому, как первый символ метки, за которым следует символ "". Специальный список "*", если он присутствует в поле Accept-Language, согласуется с любой меткой.
Замечание. Это использование префикса не предполагает, что языковые метки присвоены языкам таким образом, что, если пользователь понимает язык с определенной меткой, то он поймет все языки, имеющие метки с одним и тем же префиксом. Правило префикса просто позволяет использовать префиксные метки для случаев, когда это справедливо.
Фактор качества, присваиваемый языковой метке с помощью поля Accept-Language, равен значению качества самого длинного списка языков в поле. Если в поле отсутствует список языков, фактору качества присваивается значение нуль. Если в запросе отсутствует заголовок Accept-Language, серверу следует предполагать, что все языки приемлемы в равной мере. Если заголовок Accept-Language имеется, тогда все языки, которым присвоен фактор качества больше нуля, приемлемы.
Посылка заголовка Accept-Language с полным списком языковых предпочтений пользователя в каждом запросе может восприниматься как нарушение принципов конфиденциальности.
Так как степень интеллигентности в высшей степени индивидуальна, рекомендуется, чтобы приложения клиента делали выбор языковых предпочтений доступным для пользователя. Если выбор не сделан доступным, тогда поле заголовка Accept-Language не должно присутствовать в запросе.
Поле Accept-Ranges
Поле заголовка отклика Accept-Ranges позволяет серверу указать доступность байтдиапазонных запросов к ресурсу:
AcceptRanges = "Accept-Ranges" ":" acceptableranges
acceptableranges = 1#rangeunit | "none"
Исходные серверы, которые воспринимают байтдиапазонные запросы, могут послать
Accept-Ranges: bytes
но делать это необязательно. Клиенты могут выдавать байтдиапазонные запросы, не получив этот заголовок отклика для запрашиваемого ресурса. Серверы, которые не могут работать с какими-либо диапазонными запросами, могут передать
Accept-Ranges: none,
чтобы посоветовать клиенту не пытаться посылать такие запросы.
Поле Age
Поле заголовка отклика Age передает оценку отправителем времени с момента формирования отклика исходным сервером (или перепроверки его пригодности). Кэшированный отклик является свежим, если его возраст не превышает его времени жизни.
Age = "Age" ":" agevalue
agevalue = deltaseconds
Значения Age являются неотрицательным десятичным целым числом, характеризующим возраст записи в секундах.
Если кэш получает величину больше, чем наибольшее положительное число, которое он может себе представить, или если вычисление возраста вызвало переполнение, он должен передать заголовок Age со значением 2147483648 (231). Кэши HTTP/1.1 должны посылать заголовки Age в каждом отклике. Кэшам следует использовать арифметический тип чисел не менее 31 бита.
Поле Allow
Поле заголовка объекта Allow перечисляет набор методов, которые поддерживаются ресурсом, идентифицированным Request-URI. Целью этого поля является точное информирование получателя о рабочих методах данного ресурса. Поле заголовка Allow должно быть представлено в отклике 405 (Method Not Allowed).
Allow = "Allow" ":" 1#method
Пример использования:
Allow: GET, HEAD, PUT
Это поле не препятствует клиенту испытать другие методы. Однако указания, данные в значение поля заголовка Allow, следует выполнять. Действительный набор методов определяется исходным сервером во время каждого запроса.
Поле заголовка Allow может быть прислано запросом PUT, чтобы рекомендовать методы, которые будут поддерживаться новым или модифицированным ресурсом. Серверу не обязательно поддерживать эти методы, но ему следует включить заголовок Allow в отклик, чтобы сообщить действительно поддерживаемые методы.
Прокси не должен модифицировать поле заголовка Allow, даже если он не понимает все специфицированные методы, так как агент пользователя может иметь другие средства связи с исходным сервером.
Поле заголовка Allow не указывает на то, что методы реализованы на уровне сервера. Серверы могут использовать поле заголовка отклика Public, чтобы описать, какие методы реализованы на сервере.
Авторизация
Агент пользователя, который хочет авторизовать себя на сервере может сделать это после получения отклика 401, включив в запрос поле заголовка Authorization. Значение поля Authorization состоит из идентификационной информации агента пользователя для области ( realm ) запрошенных ресурсов.
Authorization = "Authorization" ":" credentials
Если запрос идентифицирован и область определена, та же самая идентификационная информация может быть использована для других запросов в пределах данной области.
Когда кэш коллективного пользования получает запрос, содержащий поле Authorization, он не должен присылать соответствующий отклик в качестве ответа на какой-либо другой запрос, если только не выполняется одно из следующих условий:
1. если отклик включает в себя директиву Cache-Control proxyrevalidate, кэш может применять этот отклик при последующих запросах, но проксикэш должен сначала перепроверить его пригодность с помощью исходного сервера, используя заголовки нового запроса для того, чтобы исходный сервер мог идентифицировать новый запрос;
2. если отклик содержит в себе директиву Cache-Control mustrevalidate, кэш может применять этот отклик при ответах на последующие запросы, но все кэши должны сначала перепроверить пригодность откликов с помощью исходного сервера, используя заголовки нового запроса для того, чтобы сервер мог идентифицировать новый запрос;
3. если отклик содержит директиву Cache-Control public, то этот отклик может быть отослан в ответ на любой последующий запрос.
Поле Cache-Control
Поле общего заголовка Cache-Control используется для спецификации директив, которые должны исполняться всеми механизмами кэширования вдоль цепочки запрос/отклик. Директивы определяют поведение, которое, как предполагается, должно предотвратить нежелательную интерференцию откликов или запросов в кэше. Эти директивы обычно переписывают алгоритм кэширования, используемый по умолчанию. Директивы кэша являются однонаправленными: присутствие директивы в запросе не предполагает, что та же директива будет присутствовать и в отклике.
Заметьте, что кэши HTTP/1.0 могут не реализовывать управление (Cache-Control), а только использовать директиву Pragma: no-cache.
Директивы кэша должны пропускаться через приложения прокси или внешнего шлюза (gateway), вне зависимости от их значения для этого приложения, так как директивы могут быть применимы для всех получателей в цепочке запрос/отклик. Невозможно специфицировать директивы для отдельных кэшей.
Cache-Control = "Cache-Control" ":" 1#cache-directive
cache-directive = cache-request-directive
cache-request-directive | cache-response-directive
= "nocash" ["=" <">1#field-name<">]
| "no-store"
| "max-age" "=" delta-seconds
| "max-stale" [ "=" delta-seconds ]
| "min-fresh" "=" delta-seconds
| "only-if-cached"
| cache-extension
cache-response-directive = "public"
| "private" [ "=" <"> 1#field-name <"> ]
| "no-cache" [ "=" <"> 1#field-name <"> ]
| "no-store"
| "no-transform"
| "must-revalidate"
| "max-age" "=" delta-seconds
| cache-extension;
cache-extension = token [ "=" ( token | quoted-string ) ]
Если директива появляется без какого-либо параметра 1#field-name, она воздействует на весь запрос или отклик. Когда такая директива приходит с параметром 1#field-name, она воздействует только на именованное поле или поля и не имеет никакого действия на остальную часть запроса или отклика. Этот механизм поддерживает расширяемость. Реализации будущих версий протокола HTTP могут использовать эти директивы для полей заголовка, не определенных в HTTP/1.1.
Директивы управления кэшем могут быть разделены на следующие категории.
Ограничения на то, что можно кэшировать. Они налагаются только исходным сервером.
Ограничения на то, что можно записывать в память кэша; определяются исходным сервером или агентом пользователя.
Модификации базового механизма контроля годности записей вносятся либо исходным сервером, либо агентом пользователя.
Управление процессом перепроверки годности записей и перезагрузкой осуществляется только агентом пользователя.
Управление преобразованием объектов.
Расширения системы кэширования.
Что допускает кэширование?
По умолчанию отклик допускает кэширование, если требования метода запроса, поля заголовка запроса и код статуса отклика указывают на то, что кэширование не запрещено. Следующие Cache-Control директивы отклика позволяют исходному серверу переписать стандартные требования по кэшируемости.
public
Указывает, что отклик может кэшироваться любым кэшем, даже если он в норме не кэшируем или кэшируем только в кэшах индивидуального пользования.
private
Указывает, что все сообщение отклика или его часть предназначена для одного пользователя и не должна быть записана кэшем коллективного пользования. Это позволяет исходному серверу заявить о том, что специфицированные части отклика предназначены только для одного пользователя и он не может отсылаться в ответ на запросы других пользователей. Частный кэш может кэшировать такие отклики.
Использование слова "частный" (private) определяет только возможность кэширования и не гарантирует конфиденциальности для содержимого сообщения. Платные серверы должны принимать дополнительные меры безопасности, например, шифрование
no-cache
Указывает, что все сообщениеотклик или или его фрагмент не должны кэшироваться где бы то ни было. Это позволяет исходному серверу предотвратить кэширование даже для кэшей, сконфигурированных для рассылки устаревших откликов.
Большинство кэшей HTTP/1.0 не распознают и не исполняют директиву no-cache.