Это просто пост-памятка, чтоб навести порядок в знаниях. Итак, что интересного есть внутри протокола HTTP/1.0 для разработчика веб-приложений? Как всё работает по стандарту и на практике?
Методы
HTTP/1.0 содержит следующие методы: GET (получение данных), POST (создание), PUT (создание или изменение), DELETE (удаление), HEAD, LINK и UNLINK.
LINK и UNLINK — задуманы для установления связи между ресурсами, не используются на практике и интереса не представляют.
HEAD отличается от GET только тем, что не содержит тело ответа и не поддерживает условный запрос (If-Modified-Since). На практике используется только чтобы удостовериться, что ресурс существует. GET и HEAD кэшируются.
Что интересно — ни от одного из методов не требуется идемпотентности, однако есть интересная оговорка, что только POST может создать ресурс (сервер в этом случае должен вернуть код состояния 201, а в тексте сообщения описать, что он создал). В описании метода также PUT впрочем, также сказано, что он тоже может создать ресурс, если данных достаточно.
PUT отличается от POST только смыслом, вкладываемым в имя ресурса: для POST это адрес какого-то обработчика данных, а для PUT – это именно идентификатор ресурса. POST не кэшируется. Про кеширование PUT и DELETE ничего не сказано, но логично предположить, что оно также невозможно.
Нужно отметить, что на практике далеко не всегда можно послать запросы PUT и DELETE. Поэтому их часто заменяют на POST, а дополнительную информацию об операцию производить передают косвенно. Например, для эмуляции DELETE можно просто оставить пустым тело запроса. А Google в своих протоколах использует поле X-HTTP-Method-Override для переопределения POST на PUT или DELETE.
Коды состояния
HTTP/1.0 описывает следующие коды состояния:
200 (OK) — стандартный ответ, означает что операция успешно завершена, тело ответа содержит подробности; 201 (Создан) — возвращается в ответ на POST и PUT, означает, что ресурс создан, а тело ответа содержит подробности, например, адрес созданного ресурса; 202 (Принято) — означает, что запрос принят к рассмотрению, но еще не выполнен. Логично предположить, что возвращается в ответ на POST, PUT, DELETE. Тело ответа содержит подробности, например, где смотреть прогресс исполнения; 204 (Нет содержимого) — тоже самое, что и 200, но для случая когда тела ответа нет. Агент пользователя, получив такой ответ не меняет текущий вид документа; 300 (Множественный выбор) — не используется; 301 (Постоянно перенесен), 302 (Временно перемещен) — запрос будет повторен с новым, присланным адресом. Новый адрес ресурса передается как поле Location в заголовке ответа. Коды можно возвращать в ответ на GET и не следует возвращать в ответ на POST, PUT, DELETE, т.к. в этом случае агент пользователя должен запросить подтверждения пользователя на повтор операции. Тело ответа должно содержать пояснения; 304 (Не модифицирован) — можно вернуть как ответ на условный GET. Означает, что сообщение не изменилось и можно использовать ранее кэшированное. А вот поля ответа расцениваются как новая информация. Тело ответа должно отсутствовать; 400 (Испорченный запрос), 502 (Ошибка шлюза) — низкоуровневые ошибки http-сервера; 401 (Не санкционировано) — означает, что выполнение запроса требует аутентификации. Причем не любой, а именно стандартной, описанной в стандарте протокола. Поскольку такие случаи редки, это делает данный код неупотребимым; 403 (Запрещено) — означает, что доступ к ресурсу или метод запрещены. Также может использоваться вместо 404 если нельзя сообщать пользователю информацию об отсутствии ресурса; 404 (Не найден) — означает, что ресурс с таким адресом не найден; 500 (Внутренняя ошибка сервера) — именно это и означает; 501 (Не реализовано) — именно это и означает; 503 (Сервис недоступен) — применяется при плановом отключении функционала сервера. Следует возвращать поле Retry-After для информирования агента, когда ему повторить запрос. поля запросов
Pragma — используется только со значением no-cache. В этом случае использование кэшированных данных запрещается, соответственно прокси должен передать запрос далее, и клиент сможет получить гарантированно свежий ответ. Теоретически сервер тоже может посылать такое поле, но смысл такого действия в протоколе не определен и перекладывается на получателя.
Authorization — применяется для при аутентификации пользователя, ничем не интересно.
From — предназначен для отсылки почтового адреса пользователя, но только если пользователь разрешит. OMG. Сложно сказать, что творилось в голове разработчиков стандарта, когда они это сочиняли.
If-Modified-Since — очень интересное поле. Применяется только с GET и его наличие превращает запрос в “условный”. Алгоритм работы: если дата в поле валидна, ресурс с запрошенного времени не изменялся и код результата определенно будет 200, то вместо 200 следует вернуть 304. Таким образом экономим трафик или обновляем кэш.
Referer — в этом поле агент может указать адрес, где агент узнал адрес запрашиваемого ресурса. Пересылается далеко не всегда, и часто режется прокси.
User-Agent — в этом поле клиент указывает информацию о себе. Может и не соответствовать действительности.
Accept — в этом поле агент указывает ответ какого MIME-типа он желал бы получить. Обработка этого поля — это забота веб-сервера, что конечному разработчику обычно не интересно. Достаточно знать, что сервер может отдавать ответ блоками, т.н. chunks.
Accept-Charset — в этом поле агент указывает желаемую кодировку ответа. Поскольку практика давно показала, что кроме UTF-8 ничего применять нельзя, то особого интереса поле не представляет.
Accept-Encoding — в этом поле агент указывает возможную компрессию ответа. Поскольку компрессией контента обычно занимается отдельный сервер, и делает он это автоматически, то особого интереса поле не представляет.
Accept-Language — желаемый язык контента в ответе.
поля ответов
Date — дата запроса/ответа. Теоретически клиент тоже может послать такое поле, но смысл? А вот серверу всегда следует посылать такое поле, т.к. эта дата активно используется при кешировании и более того, если этого не делать, то клиент назначит эту дату самостоятельно.
Location — указывается для ответов 300/301/302 и означает новый адрес запрашиваемого ресурса.
Server — поле в котором сервер может указать информацию о себе. Интересно, но абсолютно бесполезно.
WWW-Authenticate — применяется для при аутентификации пользователя, ничем не интересно.
Allow — в этом заголовке сервер может перечислить методы, которые он поддерживает для указанного адреса. Почему-то нельзя возвращать это поле при POST-запросах. WTF. OMG. На практике, впрочем, всё равно не применяется.
Content-Encoding — если ответ сжат, то в этом поле указан метод сжатия;
Content-Length — это поле обязательно заполняется сервером если в ответе присутствует тело ответа. Если равно нулю, то считается, что тело ответа есть, но пустое.
Content-Type — содержит MIME-тип ответа и кодировку. Если кодировка не указана, то считается что она ISO-8859-1.
Expires — содержит дату, после которой ответ сервера считается протухшим. Точнее, если дата поля Expires меньше или равна дате поля Date, то клиент должен прекратить использование кэшированных данных. Ноль и невалидная дата также должны рассматриваться агентом как указание на незамедлительное протухание кэша. Действие поля не распространяется на использование кнопки “Назад” в браузере, так что обычно в этом случае возьмутся данные из кэша.
Last-Modified — дата последнего изменения передаваемого документа. Не может быть больше значения поля Date. В стандарте сказано, что если у получателя есть копия сообщения более старого, чем указывает заголовок Last-Modified, то можно считать эту копию протухшей. Поскольку новое сообщение и так затрет старое в кэше, то очевидно, это имеет смысл только для ответов без тела сообщения: HEAD, 204, 304. Что в свою очередь, если подумать, практического смысла не несет. Такое вот загадочное поле.
Content-Language — язык ответа.
Retry-After — поле только для кода 503. Информирует агента об интервале повторения запроса. На практике игнорируется мозиллой.
Title — заголовок/название ответа. Теоретически может пригодиться при передаче простых текстовых файлов. На практике похоже что браузеры этот заголовок вообще не понимают для любых типов возвращаемого контента.
URI — может содержать несколько адресов, по которым может быть идентифицирован и может быть доступен запрошенный ресурс.
ОБЩИЕ поля
Link — для методов LINK и UNLINK содержит информацию о связываемом ресурсе.
MIME-Version — в стандарте сказано, что его следует игнорировать. О как.
Выводы
Легко заметить, что стандарт местами весьма противоречив и исключительно бестолково написан. В следующей версии, HTTP/1.1, порядка немного добавили. С практической точки зрения, для разработчика веб-сервисов представляют интерес только методы GET, POST, PUT, DELETE и поля Pragma, Date, Expires, If-Modified-Since, Referer, User-Agent, Location, Content-Type, Retry-After. Не так уж и много. С некоторым удивлением осознал бесполезность поля Last-Modified.