Немного про HTTP-протокол

Протокол HTTP вот уже на протяжении 17 лет является самым используемым протоколом в сети интернет. Почему? Всё тривиально — он простой, быстрый и достаточно надёжный, а самое главное гибкий. Основной его задачей является запрос данных с веб-сервера, в основном это сайты.

Построен он по принципу «клиент-сервер», то есть клиент (браузер) посылает запросы на сервер (apache, nginx, ligthttp) и в случае успешного соединения, в ответ на запрос, сервер отправляет клиенту информацию.

Под «информацией», в случает с HTTP, можно понимать практически всё что угодно. Связано это с упомянутой «гибкостью»: протокол способен передавать потоковый звук и видео, или же может выступать в виде транспорта для других протоколов.

Теперь рассмотрим как именно происходит коммуникация между клиентом и сервером. Мы уже определили что клиент посылает запрос, который состоит из 3-х частей:

  1. Стартовая строка — в ней указывается тип сообщения.
  2. Заголовки — описывают тело сообщения, определяя его параметры.
  3. Тело сообщения — само сообщение, должно отделяться пустой строкой.

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

Для запроса и ответа стартовые строки разные. Стартовая строка запроса выглядит вот так:

метод URI HTTP/версия

Где

  • метод — это метод запроса.
  • URI — это адрес к запрашиваемому ресурсу (документ, файл, скрипт, и т.д).
  • версия — это версия протокола (правда тут есть тонкость, о них будет ниже).

Остановимся более подробно на методах.

Методы HTTP

Методы в HTTP это своего рода инструкции, передаваемые в сообщении серверу. Синтаксически — это специально-зарезервированное слово на английском языке. Особое внимание нужно обратить на регистр: метод пишется всегда в верхнем регистре.

Будем рассматривать методы по степени их популярности:

GET

Пожалуй самый важный метод. Он используется для запроса данных с ресурса, если эти данные имеют URL. Так же с помощью этого метода начинаются какие либо действия. Метод GET относится к числу идемпотентных для сервера, это значит, что многократное выполнение одного и того же запроса не будет приводить к разным результатам.

Клиент может передавать параметры запроса в самом URI, после символа «?»:

GET /path/resource?param1=value1&param2=value2 HTTP/1.1

POST

Метод POST занимается отправкой данных, находящихся в теле сообщения, на сервер. Также часто используется для отправки информации из веб-форм и файлов. Простейший пример — написание поста на форуме или комментария в соцсети. После того, как вы написали ваше сообщение, браузер формирует POST-запрос и в его тело помещает ваше сообщение,а затем отправляет его на сервер.

Метод POST для сервера виден как неидемпотентный, и выполнение одного и того же запроса может приводить к разным ответам.

Помимо всего прочего, этот метод часто используют вместо метода GET в связи с ограничением кол-ва знаков в URL у оного, или если используется специфичная кодировка.

HEAD

Данный метод похож на метод GET, но имеет более простую функцию. Он запрашивает у сервера только лишь мета-данные, и, соответственно, из ответа исключается тело сообщения. В основном это удобно для получения информации о файлах не скачивая их. Еще методом HEAD можно проверить валидность URI.

PUT

Этот метод нужен для загрузки данных на указанный URL. Данный метод предпочтительно использовать при передаче больших объёмов информации.

OPTIONS

Данный метод запрашивает конфигурацию сервера, это полезно для определения совместимости клиента и сервера, и соответственно, для использования правильных и понятных методов. Так же можно использовать метод OPTIONS как некий аналог команды ping — для определения работоспособности сервера.

Выглядит это так:

OPTIONS * HTTP/1.1

Вот мы и рассмотрели основные методы. Конечно же их гораздо больше, но остальные очень специфичны.

URI

Как мы помним, после методов в стартовой строке идёт URI (это почти как URL).

Вы наверное сразу узнали эту аббревиатуру. И действительно, URL — это символьная ссылка. Основное различие между URL и URI это то, что первый указывает непосредственно только на ресурс, а последний идентифицирует его. Принято считать, что URI включает в себя URL.

Пример URI:

http://ru.wikipedia.org/wiki/URI

Версия HTTP

Последняя часть стартовой строки это версия HTTP.

Указание версии является скорее справочной информацией для сервера, нежели жестким указанием версии на которой нужно работать. Получая запрос сервер сравнивает свою версию с клиентской и определяет какой вид и какие правила оформления ответа следует использовать. Например, на сервере установлена версия 1.0, а в запросе указана версия 1.1. В таком случае сервер ответит в формате 1.0, это нормально, ведь более новая версия поддерживает более старые.

Заголовки

Перейдём к рассмотрению следующего важного момента — заголовки. Они используются для передачи служебной информации.

Заголовки делятся на 4 группы:

  • Основные заголовки — обязательно включаются в любое сообщение клиента и сервера.
  • Заголовки запроса — можно встретить только в запросах от клиента.
  • Заголовки ответа — можно встретить только в ответах от сервера.
  • Заголовки сущности — описывают сущность каждого сообщения (может относиться как к клиенту, так и к серверу).

С помощью заголовков можно передавать или получать обширный спектр информации и параметров, которые могут оказаться полезными в решении многих задач. Все заголовки подробно описаны в RFC. Однако можно вводить свои, только нужно следить за тем, чтобы не возникало дублирования, иначе возможны ошибки.

Вот основные (общие) заголовки, которые встречаются и в запросах и в ответах:

  • Cache-Control — параметры управления кэшированием.
  • Connection — информация о соединении.
  • Date — дата создания сообщения.
  • Pragma — специфические опции для выполнения.
  • Transfer-Encoding — перечень кодировок, применённых для формирования сообщения.
  • Upgrade — перечень протоколов, с которыми может работать клиент. Сервер указывает один.
  • Via — история прохождения запроса через прокси сервера, с указанием версии протокола.

Далее идут заголовки запроса, встречаются только в клиентских запросах:

  • Accept — перечень форматов, с которыми работает ресурс. Остальные игнорируются.
  • Accept-Charset — список кодировок с которыми может работать клиент.
  • Accept-Encoding — список кодировок, применяемых при кодировании сущности при передаче.
  • Accept-Language — перечень языков, с которыми может работать клиент.
  • Host — указание доменного имени и порта хоста для запрашиваемого ресурса. Нужно для работы виртуальных хостингов.
  • Max-Forwards — указывает предельное кол-во переходов по Proxy серверам.
  • Referer — указывает URI ресурса, с которого клиент сделал запрос.
  • User-Agent — перечень названий и версий компонентов системы клиента.

Теперь обратимся к заголовкам ответа:
  • Location — указывает URI ресурса или URI, на который нужно перейти.
  • Public — перечисляет доступные методы, подобно Allow, но для всего сервера.
  • Server — перечень названий и версий ПО на сервере, для прокси это поле Via.

И в конце рассмотрим заголовки-сущности. Они могут в запросах и ответах.

Общие:

  • Content-Encoding — указывает способ кодирования сущности.
  • Content-Language — язык содержимого.
  • Content-Length — размер сообщения выраженный в октетах.
  • Content-Location — резервное расположение сущности.
  • Content-MD5 — MD5-хэш для проверки целостности полученных данных.
  • Content-Type — способ и формат отображения сущности.
  • Link — ссылка на связанный с сущностью ресурс.
  • Title — заголовок сущности.

Для ответов:

  • Allow — перечень методов, поддерживаемых именно этим ресурсом.

Коды состояний

И в конце, последний штрих — коды состояний.

Они используются для определения состояния запроса, разделены на 5 групп. Каждая группа имеет собственный «общий смысл»:

  • 1xx — информационные. Они описывают процесс передачи.
  • 2xx — успешные. Эти говорят нам об успешной передаче.
  • 3xx — перенаправленные. Эти же сигнализируют о перенаправлении запроса.
  • 4xx — ошибка клиента. Ошибки в запросе, синтаксисе, хосте обращения и т.д.
  • 5xx — ошибка сервера. Ошибки в выполнении запроса ,связанные с сервером.

Некоторые из следующих кодов могут быть вам знакомы:

  • 200 ОК — означает что всё в порядке, запрос обработан и дан ответ.
  • 301 Moved Permanently — означает что нужный документ перенесён на другой URI. Новый адрес указывается в заголовке Location.
  • 302 Found(v1.1), Moved Temporarily(v1.0) — указывает на то, что нужный документ временно перенесён на другой URI, который находится в заголовке Location.
  • 400 Bad Request — означает что в запросе допущена синтаксическая ошибка.
  • 401 Unauthorized — означает что для доступа нужно пройти аутентификацию.
  • 403 Forbidden — не хватает прав доступа для выполнения запроса.
  • 404 Not Found — сервер не может найти запрошенный URI.
  • 500 Internal Server Error — любая ошибка сервера, если она не подходит под любой другой код ответа.

Живые примеры

На сайте PortScan.ru вы можете посмотреть параметры GET-запроса вашего браузера. А так же посмотреть какой код состояния и заголовки возвращает любой сервер.

Теперь, после рассмотрения всех основных частей запросов и ответов интересно будет посмотреть, как же браузеры формируют запросы, отсылают их, и получают ответы.

Как мы помним, минимальный вид корректного запроса выглядит примерно так:

GET / HTTP/1.1
Host: targethost

В ответ, скорее всего, можем получить нечто следующее:

HTTP/1.1 200 OK
Server: Apache/2.2.16 (Debian)
Content-Type: application/octet-stream
Content-Length: 0
Date: Tue, 30 Jul 2013 06:31:34 GMT
X-Varnish: 2908054794
Age: 0
Via: 1.1 varnish
Connection: keep-alive
X-Varnish-Cache: MISS

Однако, как не сложно догадаться минимальный вид не используется повсеместно. Вот как выглядят запросы и ответы в популярных браузерах:

Google Chrome

Запрос:

Host: portscan.ru
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36
DNT: 1
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4

Ответ:

HTTP/1.1 200 OK
Date: Wed, 31 Jul 2013 11:21:54 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=5
Server: Apache
Cache-Control: max-age=0
Expires: Wed, 31 Jul 2013 11:21:54 GMT

После заголовка, через пустую строку идёт тело сообщения: собственно сайт.

Mozilla Firefox

Запрос:

GET / HTTP/1.1
Host: portscan.ru
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Cache-Control: max-age=0

Ответ:

HTTP/1.1 200 OK
Date: Wed, 31 Jul 2013 11:25:47 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=5
Server: Apache
Cache-Control: max-age=0
Expires: Wed, 31 Jul 2013 11:25:47 GMT

Internet Explorer 10

Запрос:

GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: ru-RU
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0; NP06)
Accept-Encoding: gzip, deflate
Host: portscan.ru
DNT: 1
Connection: Keep-Alive

Ответ:

HTTP/1.1 200 OK
Date: Wed, 31 Jul 2013 11:27:30 GMT
Content-Type: text/html; charset=UTF-1251
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=5
Server: Apache
Cache-Control: max-age=0
Expires: Wed, 31 Jul 2013 11:27:30 GMT