Гипертекстный протокол HTTP
Поля заголовка отклика
Поля заголовка отклика позволяют серверу передавать дополнительную информацию об отклике, который не может быть помещен в статусную строку. Эти поля заголовка дают информацию о сервере и доступе к ресурсу, идентифицированному Request-URI.
Responseheader = Age | Location | Proxy-Authenticate | Public | Retry-After | Server | Vary | Warning | WWWAuthenticate
Имена полей заголовка отклика могут быть расширены только в случае изменения версии протокола. Однако новые или экспериментальные поля могут быть введены с учетом семантики полей заголовка отклика, если все участники обмена способны распознавать эти поля. Неузнанные поля заголовка рассматриваются как поля заголовка объекта (entityheader fields).
Объект (Entity)
Сообщения запрос и отклик могут нести в себе объект, если это не запрещено методом запроса или статусным кодом отклика. Объект состоит из полей заголовка объекта и тела объекта, хотя некоторые отклики включают в себя только заголовки объектов.
В данном разделе как отправитель, так и получатель соотносятся к клиенту или серверу, в зависимости от того, кто отправляет и кто получает объект.
Поля заголовка объекта
Поля заголовка объекта определяют опционную метаинформацию о теле объекта или, если тело отсутствует, о ресурсе, идентифицированном в запросе.
Entityheader = Allow | ContentBase | Content | ContentLanguage | ContentLength | ContentLocation | ContentMD5 | ContentRange | Content-Type | Etag | Expires | Last-Modified | extensionheader extensionheader = messageheader
Механизм расширения заголовка позволяет определить дополнительные поля заголовка объекта без изменения версии протокола, но эти поля не могут считаться заведомо распознаваемыми получателем. Неузнанные поля заголовка рекомендуется получателю игнорировать и переадресовывать проксисерверам.
Тело объекта
Тела объекта (если они имеются), пересылаемые HTTPзапросом или откликом, имеют формат и кодировку, определенную полями заголовка объекта.
entitybody = *OCTET
Тело объекта присутствует в сообщении, только когда имеется тело сообщения. Тело объекта получается из тела сообщения путем декодирования любого транспортного кода (Transfer-Encoding), который может быть применен для обеспечения безопасной и корректной доставки.
Тип
Когда тело объекта включено в сообщение, тип данных этого тела определяется полями заголовка Content-Type и Content-Encoding. Они определяют два слоя, заданных моделью кодирования:
entitybody := Content-Encoding( Content-Type( данные ) )
Content-Type специфицирует тип среды данных.
Content-Encoding может использоваться для индикации любого дополнительного кодирования содержимого поля данных, обычно для целей архивации, которая является особенностью запрашиваемого ресурса. По умолчанию никакого кодирования не применяется.
Любое HTTP/1.1 сообщение, содержащее тело объекта, должно включать поле заголовка Content-Type, определяющее тип среды для данного тела. Только в случае, когда тип среды не задан полем Content-Type, получатель может попытаться предположить, каким является тип среды, просмотрев содержимое и/или расширения имен URL, использованного для идентификации ресурса. Если тип среды остается неизвестным, получателю следует рассматривать его как application/octetstream (поток октетов).
Длина тела объекта равна длине тела сообщения, после того как произведено транспортное декодирование.
Соединения. Постоянные соединения. Цель
Прежде чем установить постоянную связь, следует реализовать отдельное TCP соединение с тем, чтобы получить URL. Это увеличивает нагрузку HTTP серверов и вызывает перегрузку каналов. Использование изображений и другой связанной с этим информации часто требует от клиента множественных запросов, направленных определенным серверам за достаточно короткое время. Анализ этих проблем содержится в [7.30],[7.27], а результаты макетирования представлены в [7.26].
Постоянное HTTP соединение имеет много преимуществ.
- При открытии и закрытии TCP соединений можно сэкономить время CPU и память, занимаемую управляющими блоками протокола TCP.
- HTTP запросы и отклики могут при установлении связи буферизоваться (pipelining), образуя очередь. Буферизация позволяет клиенту выполнять множественные запросы, не ожидая каждый раз отклика и используя одно соединение TCP более эффективно и с меньшими потерями времени.
- Перегрузка сети уменьшается за счет сокращения числа пакетов, сопряженных с открытием и закрытием TCP соединений, предоставляя достаточно времени для детектирования состояния перегрузки.
- HTTP может функционировать более эффективно, так как сообщения об ошибках могут доставляться без потери TCP связи. Клиенты, использующие будущие версии HTTP, могут испытывать новые возможности, взаимодействуя со старым сервером, но после неудачи могут попробовать старую семантику. HTTP реализациям следует пользоваться постоянными соединениями.
Общие процедуры
Заметным различием между HTTP/1.1 и более ранними версиями HTTP является постоянное соединение, которое в HTTP/1.1 является вариантом, реализуемым по умолчанию. Поэтому, если не указано обратное, клиент может предполагать, что сервер будет поддерживать постоянное соединение.
Постоянное соединение обеспечивает механизм, с помощью которого клиент и сервер могут сигнализировать о закрытии TCP-соединения. Эта система сигнализации использует поле заголовка Connection. Как только поступил сигнал о закрытии канала, клиент не должен посылать какие-либо запросы по этому каналу.
Согласование
HTTP/1.1 сервер может предполагать, что HTTP/1.1 клиент намерен поддерживать постоянное соединение, если только в поле заголовка Connection не записана лексема close. Если сервер принял решение закрыть связь немедленно после посылки отклика, ему рекомендуется послать заголовок Connection, включающий лексему связи close.
Клиент HTTP/1.1 может ожидать, что соединение останется открытым, но примет решение, оставлять ли его открытым, на основе того, содержит ли отклик сервера заголовок Connection с лексемой close.
Если клиент или сервер посылает лексему close в заголовке Connection, этот запрос становится последним для данного соединения.
Клиентам и серверам не следует предполагать, что соединение будет оставаться постоянным для версий HTTP, меньших 1.1, если только не получено соответствующее уведомление.
Буферизация
Клиенты, которые поддерживают постоянное соединение, могут буферизовать свои запросы (то есть, посылать несколько запросов не дожидаясь отклика для каждого из них). Серверы должны посылать свои отклики на эти запросы в том же порядке, в каком они их получили.
Клиенты, которые предполагают постоянство соединения и буферизацию, немедленно после установления соединения должны быть готовы совершить повторную попытку установить связь, если первая буферизованная попытка не удалась. Если клиент совершает повторную попытку установления связи, он не должен выполнять буферизацию запросов, пока не получит подтверждения об установления постоянного соединения. Клиенты должны также быть готовы послать повторно свои запросы, если сервер закрывает соединение прежде, чем пришлет соответствующие отклики.
Проксисерверы
Особенно важно то, чтобы проксисерверы корректно использовали свойства поля заголовка Connection.
Проксисервер должен сигнализировать о постоянном соединении отдельно своему клиенту и исходному серверу (origin server) или другому прокси, с которым связан. Каждое постоянное соединение устанавливается только для одной транспортной связи.
Проксисервер не должен устанавливать постоянное соединение с HTTP/1.0 клиентом.
Практические соображения
Серверы обычно имеют некоторое значение таймаута, за пределами которого они уже не поддерживают более неактивное соединение. Проксисерверы могут сделать эту величины больше, так как весьма вероятно, что клиент создаст больше соединений через один и тот же сервер. Использование постоянных соединений не устанавливает никаких требований на величину этого таймаута для клиента или сервера.
Когда клиент или сервер хочет прервать связь по таймауту, ему следует послать корректное оповещение о закрытии соединения. Клиенты и серверы должны постоянно следить, не выдала ли противоположная сторона сигнал на закрытие канала, и соответственно реагировать на него. Если клиент или сервер не зафиксирует сигнал противоположной стороны, то будут бессмысленно тратиться ресурсы сети.
Клиент, сервер или прокси могут закрыть транспортный канал в любое время. Например, клиент может послать новый запрос во время, когда сервер решит закрыть пассивное соединение. С точки зрения сервера, состояние, которое предлагается закрыть, является пассивным, но с точки зрения клиента идет обработка запроса.
Это означает, что клиенты, серверы и прокси должны быть способны восстанавливаться после случаев асинхронного закрытия. Программа клиента должна заново открыть транспортное соединение и повторно передать неисполненный запрос без вмешательства пользователя, хотя агент пользователя может предложить оператору выбор, сопряженный с повторением запроса. Однако эта повторная попытка не должна повторяться при повторной неудаче.
Серверам следует всегда реагировать, по крайней мере, на один запрос при соединении, если это возможно. Серверам не следует закрывать соединение в процессе передачи отклика, если только не произошло отказа в сети или выключения клиента.
Клиенты, которые применяют постоянные соединения, должны ограничивать число одновременных связей, которые они поддерживают с конкретным сервером. Однопользовательскому клиенту рекомендуется поддерживать не более двух соединений с любым сервером или прокси. Прокси следует использовать до 2*N соединений с другим сервером или прокси, где N равно числу активных пользователей. Эти рекомендации призваны улучшить время отклика HTTP и исключить перегрузки Интернет и других сетей.
Требования к передаче сообщений
Общие требования
- HTTP/1.1 серверам следует поддерживать постоянные соединения и использовать TCP механизмы контроля информационного потока для преодоления временных перегрузок, а не разрывать соединение в расчете на то, что клиент совершит повторную попытку. Последнее может усугубить сетевую перегрузку.
- Клиент HTTP/1.1 (или более поздней версии), посылая тело сообщения, должен мониторировать сетевое соединение на наличие сигнала ошибки. Если клиент обнаружил состояние ошибки, он должен немедленно прервать передачу. Если тело передается с использованием блочной кодировки (chunked encoding), возможно применение фрагмента нулевой длины и пустой завершающей секции для обозначения преждевременного конца сообщения. Если телу предшествовал заголовок ContentLength, клиент должен разорвать соединение.
- Клиент HTTP/1.1 (или более поздней версии) должен быть готов принять код статуса 100 (Continue — продолжить), за которым следует обычный отклик.
- Сервер HTTP/1.1 (или позднейшей версии), который получает запрос от клиента HTTP/1.0 (или более ранней), не должен передавать отклик 100 ( continue — продолжение), ему следует или ждать нормального завершения запроса (таким образом, избегая его прерывания) или преждевременно разрывать соединение.
Клиентам следует запомнить номер версии, по крайней мере, сервера, с которым проводилась работа последним. Если клиент HTTP/1.1 получил отклик от сервера HTTP/1.1 (или позднейшей) и обнаружил разрыв соединения до получения какого-либо статусного кода, клиенту следует повторно попытаться направить запрос без участия пользователя. Если клиент действительно повторяет запрос, то должен:
- сначала послать поля заголовка запроса, а затем
- ждать, того, что сервер пришлет отклик 100 ( Continue ), тогда клиент продолжит работу, или код статуса, сигнализирующего об ошибке.
Если клиент HTTP/1.1 не получил отклика от сервера HTTP/1.1 (или более поздней версии), ему следует считать, что сервер поддерживает версию HTTP/1.0 или более раннюю и не использует отклик 100 ( Continue ). Если в этом случае клиент обнаруживает закрытие соединения до получения какого-либо статусного кода от сервера, следует повторить запрос. Если клиент повторил запрос серверу HTTP/1.0, ему нужно применить следующий алгоритм получения надежного отклика:
- инициировать новое соединение с сервером;
- передать заголовок запроса;
- инициализировать переменную R для оценки задержки отклика сервера (roundtrip time) (например, на основе времени установления соединения), если RTT не доступно, ему присваивается значение 5 секунд;
- вычислить T = RTT * (2N), где N равно числу предыдущих попыток запроса;
- ждать в течение Т секунд или до прихода статуса ошибки (что наступит раньше);
- если не получен сигнал ошибки, после T секунд передается тело запроса;
- если клиент обнаруживает преждевременное прерывание связи, повторяется шаг 1 до тех пор, пока запрос не будет принят или будет получен сигнал ошибки, или пока нетерпеливый пользователь не завершит процесс посылки повторных запросов.
Вне зависимости от версии сервера, если получен статус ошибки, то клиент:
- не должен продолжать операции и
- должен прервать соединение, если процедура не завершена посылкой сообщения.
Клиент HTTP/1.1 (или более поздней версии), который обнаруживает разрыв соединения после получения флага 100 (Continue), но до получения какого-либо статусного кода, должен повторить запрос и не должен ждать отклика 100 (Continue), но может и делать это, если такие действия упрощают реализацию программы.
Метод определений
Набор общих методов для HTTP/1.1 определен ниже. Хотя этот набор может быть расширен, нельзя предполагать, что дополнительные методы следуют той же семантике для разных клиентов и серверов. Поле заголовка запроса Host должно присутствовать во всех запросах HTTP/1.1.
Безопасные и идемпотентные методы. Безопасные методы
Программисты должны заботиться о том, чтобы избегать операций, которые могут иметь неожиданное значение для них самих или их соседей по сети Интернет.
В частности, установлено соглашение, что методы GET и HEAD никогда не должны выполнять какие-либо функции помимо доставки информации. Эти методы должны рассматриваться как вполне безопасные. Это позволяет агентам пользователя представлять другие методы, такие, как POST, PUT и DELETE, особым способом, так что пользователь сам будет заботиться о возможности опасных операций, которые могут быть выполнены в результате реализации запроса.
Естественно, невозможно гарантировать, что сервер не будет вызывать побочные эффекты как следствие выполнения запроса GET. В действительности, некоторые динамические ресурсы предусматривают такую возможность. Важным отличием здесь является то, что пользователь не запрашивал побочные эффекты и, следовательно, не может нести ответственность за них.
Идемпотентные методы
Методы могут также иметь свойство идемпотентности (idempotence), при котором (помимо ошибок и таймаутов) побочный эффект от N > 0 идентичных запросов является таким же, как и от одного запроса. Методы GET, HEAD, PUT и DELETE имеют это свойство.
Опции
Метод OPTIONS представляет собой запрос информации о коммуникационных опциях, доступных в цепочке запрос/отклик, идентифицированной Request-URI. Этот метод позволяет клиенту определить опции и/или требования, связанные с ресурсами, или возможности сервера, не прибегая к операциям по извлечению и пересылке каких-либо файлов.
Если отклик сервера не сигнализирует об ошибке, отклик не должен включать никакой информации об объекте, отличной от того, что считается коммуникационными опциями (напрмер, Allow подходит под эту категорию, а Content-Type — нет). Отклики на этот метод не должны кэшироваться.
Если Request-URI тождественен символу звездочка ("*"), то запрос OPTIONS будет относиться ко всему серверу. Отклик 200 должен включать в себя любые поля заголовка, которые указывают на опционные характеристики используемого сервера (например, Public ), включая любые расширения, не определенные в данной спецификации, в дополнение к любым общим используемым полям заголовка. Запрос "OPTIONS *" может быть реализован через прокси путем спецификации сервера места назначения в Request-URI без указания прохода. Если Request-URI не равен звездочке, запрос OPTIONS относится только к опциям, которые доступны при обмене с данным ресурсом. Отклик 200 должен включать любые поля заголовка, которые указывают опционные характеристики используемого сервера и применимы к данному ресурсу (например, Allow ), включая любые расширения, не описанные в данной спецификации. Если запрос OPTIONS проходит через прокси, то он должен редактировать отклик и удалять те опции, которые не доступны для реализации через данный проксисервер.
Метод GET
Метод GET предполагает извлечение любой информации (в форме объекта), заданной Request-URI. Если Request-URI относится к процессу, генерирующему данные, то в результате в виде объекта будут присланы эти данные, а не исходный текст самого процесса, если только этот текст не является результатом самого процесса.
Семантика метода меняется на условный GET, если сообщениезапрос включает в себя поля заголовка If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match или If-Range. Метод условного GET запрашивает, пересылку объекта только при выполнении требований, описанных в соответствующих полях заголовка. Метод условного GET имеет целью уменьшить ненужное использование сети путем разрешения актуализации кэшированых объектов без посылки множественных запросов или пересылки данных, которые уже имеются у клиента. Семантика метода GET меняется на частичный GET, если сообщение запроса включает в себя поле заголовка Range. Метод частичного GET ориентирован на уменьшение ненужного сетевого обмена, допуская пересылку лишь части объекта, которая нужна клиенту, и не пересылая уже имеющихся частей.
Отклик на запрос GET буферизуется тогда и только тогда, когда это согласуется с требованиями буферизации.
Метод HEAD
Метод HEAD идентичен GET за исключением того, что сервер не должен присылать тело сообщения. Метаинформация, содержащаяся в заголовках отклика на запрос HEAD, должна быть идентичной информации, посланной в отклике на запрос GET. Этот метод может использоваться для получения метаинформации об объекте, указанном в запросе, без передачи тела самого объекта. Этот метод часто применяется для тестирования гипертекстных связей на корректность, доступность и актуальность.
Отклик на запрос HEAD может кэшироваться в том смысле, что информация, содержащаяся в отклике, может использоваться для актуализации кэшированных ранее объектов данного ресурса. Если новые значения поля указывают на то, что кэшированный объект отличается от текущего объекта (как это индицируется изменением ContentLength, ContentMD5, ETag или Last-Modified ), тогда запись в кэше должна рассматриваться как устаревшая.
Метод POST
Метод POST используется при подаче заявки серверу принять вложенный в запрос объект в качестве нового вторичного ресурса, идентифицированного Request-URI в RequestLine. POST создан для обеспечения однородной схемы реализации следующих функций:
- аннотация существующего ресурса;
- помещение сообщения на электронную доску объявлений, в группу новостей, почтовый список или какуюто другую группу статей;
- выдача блока данных, такого, как при передаче формы процессу ее обработки;
- расширение базы данных с помощью операции добавления (append).
Реальная операция, выполняемая методом POST, определяется сервером и обычно зависит от Request-URI. Присланный объект является вторичным по отношению к URI в том же смысле, в каком файл является вторичным по отношению к каталогу, в котором он находится, статья новостей — вторичной по отношению к группе новостей, куда она помещена, или запись — по отношению к базе данных.
Операция, выполняемая методом POST, может не иметь последствий для ресурса, который может быть идентифицирован URI. В этом случае приемлемым откликом является 200 (OK) или 204 (No Content — никакого содержимого), в зависимости от того, включает ли в себя отклик объект, описывающий ресурс.
Если ресурс был создан на исходном сервере, отклик должен быть равен 201 (Created — создан) и содержать объект, который описывает статус запроса и относится к новому ресурсу и заголовку Location.
Отклики на этот метод не могут кэшироваться, если только не содержат поля заголовка Cache-Control или Expires. Однако отклик 303 может быть использован для того, чтобы направить агента пользователя для извлечения кэшируемого ресурса.
Запросы POST должны подчиняться требованиям, предъявляемым к передаче сообщений.
Метод PUT
Метод PUT применяется для актуализации содержимого сервера и требует, чтобы вложенный объект был запомнен с использованием Request-URI. Если Request-URI относится к уже существующему ресурсу, то вложенный объект следует рассматривать как модифицированную версию объекта на исходном сервере. Если Request-URI не указывает на существующий ресурс и запрашивающий агент пользователя может определить этот URI как новый ресурс, исходный сервер может создать ресурс с этим URI. Если новый ресурс создан, исходный сервер должен информировать об этом агента пользователя, послав код отклик 200 (OK) или 204 (No Content — никакого содержимого), тем самым объявляя об успешно выполненном запросе. Если ресурс не может быть создан или модифицирован с помощью Request-URI, должен быть послан соответствующий код отклика, который отражает характер проблемы. Получатель объекта не должен игнорировать любой заголовок Content* (например, ContentRange), который он не понял или не использовал, а должен в таком случае вернуть код отклика 501 (Not Implemented — не использовано).
Если запрос проходит через кэш и Request-URI идентифицирует один или более кэшированных объектов, эти объекты должны рассматриваться как устаревшие. Отклики этого метода не должны кэшироваться.
Фундаментальное отличие между запросами POST и PUT отражается в различных значениях Request-URI. URI в запросе POST идентифицирует ресурс, который будет работать с вложенным объектом. Этот ресурс может быть процессом приемки данных, шлюзом к другому протоколу или отдельным объектом, который воспринимает аннотации. Напротив, URI в запросах PUT идентифицируют объекты, заключенные в запросе: агент пользователя знает, какой URI применить, и сервер не должен пытаться посылать запрос другому ресурсу. Если сервер хочет, чтобы запрос был направлен другому URI, он должен послать отклик 301 (Moved Permanently). Агент пользователя может принять свое собственное решение относительно того, следует ли переадресовывать запрос.
Один и тот же ресурс может быть идентифицирован многими URI. Например, статья может иметь URI для идентификации текущей версии, которая отличается от URI, идентифицирующей каждую конкретную версию. В этом случае запрос PUT на общий URI может дать в результате несколько других URI, определенных исходным сервером. HTTP/1.1 не определяет, как метод PUT воздействует на состояние исходного сервера. Запросы PUT должны подчиняться требованиям передачи сообщения.
Метод DELETE
Метод DELETE требует, чтобы исходный сервер уничтожил ресурс, идентифицируемый Request-URI. Этот метод на исходном сервере может быть отвергнут вмешательством человека (или какимто иным путем). Клиент не может гарантировать, что операция была выполнена, даже если возвращенный статусный код указывает, что операция завершилась успешно. Однако сервер не должен сообщать об успехе, если за время отклика он не намерен стереть ресурс или переместить его в недоступное место.
Сообщение об успехе должно иметь код 200 (OK), если отклик включает объект, описывающий статус; 202 (Accepted — принято), если операция еще не произведена или 204 (No Content — Никакого содержимого), если отклик OK, но объекта в нем нет.
Если запрос проходит через кэш, а Request-URI идентифицирует один или более кэшированных объектов, эти объекты следует считать устаревшими. Отклики на этот метод не кэшируемы.
Метод TRACE
Метод TRACE используется для того, чтобы запустить удаленный цикл сообщениязапроса на прикладном уровне. Конечный получатель запроса должен отослать полученное сообщение назад клиенту в виде тела объекта ( код = 200 (OK) ). Конечным получателем является либо исходный сервер, либо первый прокси или шлюз для получения значения Max-Forwards (0) в запросе. Запрос TRACE не должен включать в себя объект.
TRACE позволяет клиенту видеть, что получено на другом конце цепи запроса и использовать эти данные для тестирования или диагностики. Значение поля заголовка Via представляет особый интерес, так как оно позволяет отследить всю цепочку запроса. Применение поля заголовка Max-Forwards позволяет клиенту ограничить длину цепи запроса, которая полезна для тестирования цепи прокси, переадресующих сообщения по замкнутому кругу.
В случае успеха отклик должен содержать все сообщениезапрос с Content-Type = message/http. Отклики этого метода не должны кэшироваться.
Определения статусных кодов
Ниже описаны статусные коды, а также то, каким методам они соответствуют и какая метаинформация должна присутствовать в откликах.
Информационный 1xx
Этот класс статусного кода индицирует информационный отклик, состоящий только из статусной строки и опционных заголовков с пустой строкой в конце. Так как HTTP/1.0 не определяет каких-либо статусных кодов 1xx, серверы не должны посылать отклики 1xx клиентам HTTP/1.0, за исключением случаев отладки экспериментальных протокольных версий.
100 Continue (продолжение)
Клиент может продолжать работу, получив этот отклик. Такой промежуточный отклик используется для информирования клиента о том, что начальная часть запроса получена и пока не отклонена сервером. Клиенту следует продолжить отправлять оставшуюся часть запроса, — если же запрос уже отправлен, то игнорировать этот отклик. Сервер должен послать окончательный отклик по завершении реализации запроса.
101 Switching Protocols (Переключающие протоколы)
Сервер оповещает клиента, что понял и принял к исполнению запрос. С помощью поля заголовка сообщения Upgrade клиент уведомляется об изменении прикладного протокола для данного соединения. Сервер переходит на протокол, определенный в поле заголовка отклика Upgrade, немедленно после получения пустой строки, завершающей отклик 101.
Протокол следует изменять лишь в случае, если он предоставляет существенные преимущества. Например, переключение на новую версию HTTP предоставляет преимущества по отношению к старой версии, а переключение на синхронный протокол реального времени может иметь преимущество, когда ресурс использует это свойство.