HTTP request и response могут содержать так называемое тело (body).
Мы уже знаем, что сам HTTP запрос состоит из заголовков и опционального тела запроса. Для отделения заголовков от тела существуют определенные правила. Давайте посмотрим на примере, как работать с body и каким образом посылать какие-то данные кроме заголовков. Сделаем HTTP запрос к хосту hexlet.io:
В ответ мы получаем какие-то заголовки и далее идёт тело, которое нас как раз и интересует. В данном случае это не какая-то страница нашего сайта, а просто страница которую отдаёт сервер. Она связана с перенаправлением.
Если с заголовками всё понятно, они отделяются друг от друга переводом строки и для отправки мы добавляем еще один перевод, который выглядит как пустая строка. То как быть с телом запроса? Оно может содержать внутри всё что угодно. Мы не можем кодировать перевод строки как специальный символ. Ведь те самые два перевода строки могут находиться внутри тела запроса. Но существуют и другие причины по которым в текстовом протоколе нельзя просто так определить когда заканчивается тело. Если бы мы приняли ответ при отсутствии каких-то специальных механизмов, то после того как сервер отправил первые два перевода строки мы сразу увидели бы ответ и всё что посылалось дальше вообще не считалось бы частью ответа HTTP response. Для решения этой проблемы был придуман другой, более универсальный механизм. Он основан на передаче специального заголовка.
Во время отправки ответа сервер формирует специальный заголовок, который называется Content-Length. Это и есть ключ к тому как работать с body. Перед тем как отправить тело ответа, происходит вычисление его длины и записывается количество байт.
После того, как передан такой заголовок другая сторона будет ожидать ровно столько байт, сколько в нём указано. Как мы помним, для response и request это работает абсолютно одинаково. После того как был передан последний символ, соединение закрывается. Стоит уточнить, что закрывается именно HTTP-сессия. На сервере может быть активен keep-alive, но ключевой момент в том, что запрос считается завершённым и отображается.
Указание размера тела нужно не только для отправки ответа, но и при запросах, когда на сервер посылаются, например, данные формы.
В прошлой заметке, мы определились с тем, что браузер (клиент) отправляет серверу HTTP запросы, а сервер отправляет клиенту HTTP ответы. Эти запросы и ответы оформляются по определенным правилам. Есть, что-то вроде синтаксиса, как и в какой последовательности, должно быть написано. Должна быть строго определенная структура.
Давайте более подробно рассмотрим эту структуру, по которой строятся запросы и ответы в протоколе HTTP.
HTTP запрос состоит из трех основных частей, которые идут в нем именно в том порядке, который указан ниже. Между заголовками и телом сообщения находится пустая строка (в качестве разделителя), она представляет собой символ перевода строки.
1. строка запроса (Request Line)
2. заголовки (Message Headers)
Пустая строка (разделитель)
3. тело сообщения (Entity Body) – необязательный параметр
Строка запроса – указывает метод передачи, URL-адрес, к которому нужно обратиться и версию протокола HTTP.
Заголовки – описывают тело сообщений, передают различные параметры и др. сведения и информацию.
Когда мы получаем ответный запрос от сервера, тело сообщения, чаще всего представляет собой содержимое веб-страницы. Но, при запросах к серверу, оно тоже может иногда присутствовать, например, когда мы передаем данные, которые заполнили в форме обратной связи на сервер.
Более подробно, каждый элемент запроса, мы рассмотрим в следующих заметках.
Запрос от браузера:
В следующем примере уже присутствует тело сообщения.
Вот такими сообщениями обмениваются клиент и сервер по протоколу HTTP.
Все мои уроки по серверному программированию здесь.
Чтобы оставить сообщение, зарегистрируйтесь/войдите на сайт через:
HTTP (HyperText Transfer Protocol — протокол передачи гипертекста) — символьно-ориентированный клиент-серверный протокол прикладного уровня без сохранения состояния, используемый сервисом World Wide Web.
Основным объектом манипуляции в HTTP является ресурс, на который указывает URI (Uniform Resource Identifier – уникальный идентификатор ресурса) в запросе клиента. Основными ресурсами являются хранящиеся на сервере файлы, но ими могут быть и другие логические (напр. каталог на сервере) или абстрактные объекты (напр. ISBN). Протокол HTTP позволяет указать способ представления (кодирования) одного и того же ресурса по различным параметрам: mime-типу, языку и т. д. Благодаря этой возможности клиент и веб-сервер могут обмениваться двоичными данными, хотя данный протокол является текстовым.
Структура протокола¶
Структура протокола определяет, что каждое HTTP-сообщение состоит из трёх частей (рис. 1), которые передаются в следующем порядке:
Рис. 1. Структура протокола HTTP (дамп пакета, полученный сниффером Wireshark)
Стартовая строка HTTP¶
Cтартовая строка является обязательным элементом, так как указывает на тип запроса/ответа, заголовки и тело сообщения могут отсутствовать.
Стартовые строки различаются для запроса и ответа. Строка запроса выглядит так:
Стартовая строка ответа сервера имеет следующий формат:
Например, на предыдущий наш запрос клиентом данной страницы сервер ответил строкой:
Методы протокола¶
Метод HTTP (англ. HTTP Method) — последовательность из любых символов, кроме управляющих и разделителей, указывающая на основную операцию над ресурсом. Обычно метод представляет собой короткое английское слово, записанное заглавными буквами (Табл. 1). Названия метода чувствительны к регистру.
Таблица 1. Методы протокола HTTP
Метод
Краткое описание
OPTIONS
Используется для определения возможностей веб-сервера или параметров соединения для конкретного ресурса. Предполагается, что запрос клиента может содержать тело сообщения для указания интересующих его сведений. Формат тела и порядок работы с ним в настоящий момент не определён. Сервер пока должен его игнорировать. Аналогичная ситуация и с телом в ответе сервера.
Для того чтобы узнать возможности всего сервера, клиент должен указать в URI звёздочку — «*». Запросы «OPTIONS * HTTP/1.1» могут также применяться для проверки работоспособности сервера (аналогично «пингованию») и тестирования на предмет поддержки сервером протокола HTTP версии 1.1.
Результат выполнения этого метода не кэшируется.
Используется для запроса содержимого указанного ресурса. С помощью метода GET можно также начать какой-либо процесс. В этом случае в тело ответного сообщения следует включить информацию о ходе выполнения процесса. Клиент может передавать параметры выполнения запроса в URI целевого ресурса после символа «?»: GET /path/resource?param1=value1¶m2=value2 HTTP/1.1
Согласно стандарту HTTP, запросы типа GET считаются идемпотентными[4] — многократное повторение одного и того же запроса GET должно приводить к одинаковым результатам (при условии, что сам ресурс не изменился за время между запросами). Это позволяет кэшировать ответы на запросы GET.
Кроме обычного метода GET, различают ещё условный GET и частичный GET. Условные запросы GET содержат заголовки If-Modified-Since, If-Match, If-Range и подобные. Частичные GET содержат в запросе Range. Порядок выполнения подобных запросов определён стандартами отдельно.
Аналогичен методу GET, за исключением того, что в ответе сервера отсутствует тело. Запрос HEAD обычно применяется для извлечения метаданных, проверки наличия ресурса (валидация URL) и чтобы узнать, не изменился ли он с момента последнего обращения.
Заголовки ответа могут кэшироваться. При несовпадении метаданных ресурса с соответствующей информацией в кэше копия ресурса помечается как устаревшая.
Применяется для передачи пользовательских данных заданному ресурсу. Например, в блогах посетители обычно могут вводить свои комментарии к записям в HTML-форму, после чего они передаются серверу методом POST и он помещает их на страницу. При этом передаваемые данные (в примере с блогами — текст комментария) включаются в тело запроса. Аналогично с помощью метода POST обычно загружаются файлы.
В отличие от метода GET, метод POST не считается идемпотентным[4], то есть многократное повторение одних и тех же запросов POST может возвращать разные результаты (например, после каждой отправки комментария будет появляться одна копия этого комментария).
При результатах выполнения 200 (Ok) и 204 (No Content) в тело ответа следует включить сообщение об итоге выполнения запроса. Если был создан ресурс, то серверу следует вернуть ответ 201 (Created) с указанием URI нового ресурса в заголовке Location.
Сообщение ответа сервера на выполнение метода POST не кэшируется.
Применяется для загрузки содержимого запроса на указанный в запросе URI. Если по заданному URI не существовало ресурса, то сервер создаёт его и возвращает статус 201 (Created). Если же был изменён ресурс, то сервер возвращает 200 (Ok) или 204 (No Content). Сервер не должен игнорировать некорректные заголовки Content-* передаваемые клиентом вместе с сообщением. Если какой-то из этих заголовков не может быть распознан или не допустим при текущих условиях, то необходимо вернуть код ошибки 501 (Not Implemented).
Фундаментальное различие методов POST и PUT заключается в понимании предназначений URI ресурсов. Метод POST предполагает, что по указанному URI будет производиться обработка передаваемого клиентом содержимого. Используя PUT, клиент предполагает, что загружаемое содержимое соответствуют находящемуся по данному URI ресурсу.
Сообщения ответов сервера на метод PUT не кэшируются.
Аналогично PUT, но применяется только к фрагменту ресурса.
Удаляет указанный ресурс.
Возвращает полученный запрос так, что клиент может увидеть, что промежуточные сервера добавляют или изменяют в запросе.
Устанавливает связь указанного ресурса с другими.
Убирает связь указанного ресурса с другими.
Каждый сервер обязан поддерживать как минимум методы GET и HEAD. Если сервер не распознал указанный клиентом метод, то он должен вернуть статус 501 (Not Implemented). Если серверу метод известен, но он не применим к конкретному ресурсу, то возвращается сообщение с кодом 405 (Method Not Allowed). В обоих случаях серверу следует включить в сообщение ответа заголовок Allow со списком поддерживаемых методов.
Наиболее востребованными являются методы GET и POST — на человеко-ориентированных ресурсах, POST — роботами поисковых машин и оффлайн-браузерами.
Прокси-сервер
Коды состояния¶
Код состояния информирует клиента о результатах выполнения запроса и определяет его дальнейшее поведение. Набор кодов состояния является стандартом, и все они описаны в соответствующих документах RFC.
Рис. 1. Структура кода состояния HTTP
Введение новых кодов должно производиться только после согласования с IETF. Клиент может не знать все коды состояния, но он обязан отреагировать в соответствии с классом кода.
Применяемые в настоящее время классы кодов состояния и некоторые примеры ответов сервера приведены в табл. 2.
Таблица 2. Коды состояния протокола HTTP
Класс кодов
Краткое описание
1xx Informational (Информационный)
В этот класс выделены коды, информирующие о процессе передачи. В HTTP/1.0 сообщения с такими кодами должны игнорироваться. В HTTP/1.1 клиент должен быть готов принять этот класс сообщений как обычный ответ, но ничего отправлять серверу не нужно. Сами сообщения от сервера содержат только стартовую строку ответа и, если требуется, несколько специфичных для ответа полей заголовка. Прокси-сервера подобные сообщения должны отправлять дальше от сервера к клиенту.
Примеры ответов сервера:
Сообщения данного класса информируют о случаях успешного принятия и обработки запроса клиента. В зависимости от статуса сервер может ещё передать заголовки и тело сообщения.
Примеры ответов сервера:
Коды статуса класса 3xx сообщают клиенту, что для успешного выполнения операции нужно произвести следующий запрос к другому URI. В большинстве случаев новый адрес указывается в поле Location заголовка. Клиент в этом случае должен, как правило, произвести автоматический переход (жарг. «редирект»).
Обратите внимание, что при обращении к следующему ресурсу можно получить ответ из этого же класса кодов. Может получиться даже длинная цепочка из перенаправлений, которые, если будут производиться автоматически, создадут чрезмерную нагрузку на оборудование. Поэтому разработчики протокола HTTP настоятельно рекомендуют после второго подряд подобного ответа обязательно запрашивать подтверждение на перенаправление у пользователя (раньше рекомендовалось после 5-го). За этим следить обязан клиент, так как текущий сервер может перенаправить клиента на ресурс другого сервера. Клиент также должен предотвратить попадание в круговые перенаправления.
Примеры ответов сервера:
Класс кодов 4xx предназначен для указания ошибок со стороны клиента. При использовании всех методов, кроме HEAD, сервер должен вернуть в теле сообщения гипертекстовое пояснение для пользователя.
Примеры ответов сервера:
Коды 5xx выделены под случаи неудачного выполнения операции по вине сервера. Для всех ситуаций, кроме использования метода HEAD, сервер должен включать в тело сообщения объяснение, которое клиент отобразит пользователю.
Примеры ответов сервера:
Заголовки HTTP¶
Заголовок HTTP (HTTP Header) — это строка в HTTP-сообщении, содержащая разделённую двоеточием пару вида «параметр-значение». Формат заголовка соответствует общему формату заголовков текстовых сетевых сообщений ARPA (RFC 822). Как правило, браузер и веб-сервер включают в сообщения более чем по одному заголовку. Заголовки должны отправляться раньше тела сообщения и отделяться от него хотя бы одной пустой строкой (CRLF).
Название параметра должно состоять минимум из одного печатного символа (ASCII-коды от 33 до 126). После названия сразу должен следовать символ двоеточия. Значение может содержать любые символы ASCII, кроме перевода строки (CR, код 10) и возврата каретки (LF, код 13).
Пробельные символы в начале и конце значения обрезаются. Последовательность нескольких пробельных символов внутри значения может восприниматься как один пробел. Регистр символов в названии и значении не имеет значения (если иное не предусмотрено форматом поля).
Пример заголовков ответа сервера:
Все HTTP-заголовки разделяются на четыре основных группы:
Сущности (entity, в переводах также встречается название “объект”) — это полезная информация, передаваемая в запросе или ответе. Сущность состоит из метаинформации (заголовки) и непосредственно содержания (тело сообщения).
В отдельный класс заголовки сущности выделены, чтобы не путать их с заголовками запроса или заголовками ответа при передаче множественного содержимого (multipart/ * ). Заголовки запроса и ответа, как и основные заголовки, описывают всё сообщение в целом и размещаются только в начальном блоке заголовков, в то время как заголовки сущности характеризуют содержимое каждой части в отдельности, располагаясь непосредственно перед её телом.
В таблице 3 приведено краткое описание некоторых HTTP-заголовков.
Таблица 3. Заголовки HTTP
В листинге 1 приведен фрагмент дампа заголовков при подключении к серверу http://example.org
Листинг 1. Заголовки HTTP
Тело сообщения¶
Тело HTTP сообщения (message-body), если оно присутствует, используется для передачи сущности, связанной с запросом или ответом. Тело сообщения (message-body) отличается от тела сущности (entity-body) только в том случае, когда при передаче применяется кодирование, указанное в заголовке Transfer-Encoding. В остальных случаях тело сообщения идентично телу сущности.
Присутствие тела сообщения в запросе отмечается добавлением к заголовкам запроса поля заголовка Content-Length или Transfer-Encoding. Тело сообщения (message-body) может быть добавлено в запрос только когда метод запроса допускает тело объекта (entity-body).
Все ответы содержат тело сообщения, возможно нулевой длины, кроме ответов на запрос методом HEAD и ответов с кодами статуса 1xx (Информационные), 204 (Нет содержимого, No Content), и 304 (Не модифицирован, Not Modified).
Сообщения HTTP состоят из текстовой информации в кодировке ASCII, записанной в несколько строк. В HTTP/1.1 и более ранних версиях они пересылались в качестве обычного текста. В HTTP/2 текстовое сообщение разделяется на фреймы, что позволяет выполнить оптимизацию и повысить производительность.
Механизм бинарного фрагментирования в HTTP/2 разработан так, чтобы не потребовалось вносить изменения в имеющиеся APIs и конфигурационные файлы: он вполне прозрачен для пользователя.
HTTP запросы и ответы имеют близкую структуру. Они состоят из:
Запросы HTTP
Стартовая строка
Заголовки
Заголовки запроса HTTP имеют стандартную для заголовка HTTP структуру: не зависящая от регистра строка, завершаемая ( ‘:’ ) и значение, структура которого определяется заголовком. Весь заголовок, включая значение, представляет собой одну строку, которая может быть довольно длинной.
Существует множество заголовков запроса. Их можно разделить на несколько групп:
Тела можно грубо разделить на две категории:
Ответы HTTP
Строка статуса (Status line)
Стартовая строка ответа HTTP, называемая строкой статуса, содержит следующую информацию:
Пример строки статуса: HTTP/1.1 404 Not Found.
Заголовки
Заголовки ответов HTTP имеют ту же структуру, что и все остальные заголовки: не зависящая от регистра строка, завершаемая двоеточием ( ‘:’ ) и значение, структура которого определяется типом заголовка. Весь заголовок, включая значение, представляет собой одну строку.
Существует множество заголовков ответов. Их можно разделить на несколько групп:
Тела можно разделить на три категории:
Фреймы HTTP/2
Сообщения HTTP/1.x имеют несколько недостатков в отношении производительности:
Фреймы HTTP сейчас прозрачны для веб-разработчиков. Это дополнительный шаг, который HTTP/2 делает по отношению к сообщениям HTTP/1.1 и лежащему в основе транспортному протоколу. Для реализации фреймов HTTP веб-разработчикам не требуется вносить изменения в имеющиеся APIs; если HTTP/2 доступен и на сервере, и на клиенте, он включается и используется.
Заключение
Сообщения HTTP играют ключевую роль в использовании HTTP; они имеют простую структуру и хорошо расширяемы. Механизм фреймов в HTTP/2 добавляет ещё один промежуточный уровень между синтаксисом HTTP/1.x и используемым им транспортным протоколом, не проводя фундаментальных изменений: создаётся надстройка над уже зарекомендовавшими себя методами.
HTTP расшифровывается «как протокол передачи гипертекста» — это протокол связи, используемый для просмотра веб-страниц. Этот протокол использует модель на основе сообщений — клиент совершает HTTP-запрос к серверу, на который сервер отвечает ресурсом, который отображается в браузере.
Каждое взаимодействие через HTTP включает в себя запрос и ответ. По своей природе HTTP не имеет состояния.
Без состояния означает, что все запросы отделены друг от друга, а значит —каждый запрос должен содержать достаточно информации, чтобы полностью выполниться. Это означает, что каждая транзакция HTTP-модели, основанной на сообщениях, обрабатывается отдельно от остальных.
URL (унифицирован н ый указатель ресурса) — вероятно, самая известная концепция интернета. Это также одна из самых важных и полезных концепций. URL-адрес — это веб-адрес, используемый для идентификации ресурсов в интернете.
Идея интернета структурирована вокруг ресурсов, с самого начала интернет был платформой для обмена текстовыми/HTML — файлами, документами, изображениями и т.д, и поэтому он может рассматриваться как совокупность ресурсов.
Протокол (Protocol — обычно это HTTP (или HTTPS для защищённой версии HTTP)
Другие примечательные протоколы:
Домен (Domain) — имя для идентификации одного или нескольких IP-адресов, на которых расположен ресурс.
Путь (Path) — указывает местоположение ресурса на сервере. Использует ту же логику, что и расположение ресурса на устройстве, которое вы читаете в этой статье (например, /search/cars/VWBeetle.pdf или C:/mycars/VWBeetle.pdf).
Параметры (Parameters) — дополнительные данные, используемые для идентификации или фильтрации ресурса на сервере.
При поиске статей и дополнительной информации об HTTP вы можете встретить термин URI (унифицированный идентификатор ресурса). URI иногда используется вместо URL, но в основном в формальных спецификациях и людьми, которые хотят похвастаться 🙂
HTTP-запросы
В HTTP каждый запрос должен иметь URL-адрес. К тому же, запросу необходим метод. Четыре главных HTTP метода это:
Я объясню эти и другие методы в разделе «HTTP-методы» этой статьи.
Эти методы прямо соответствуют действиям:
Все HTTP-сообщения имеют один или несколько заголовков, за которыми следует необязательное тело сообщения. Тело содержит данные, которые будут отправлены с запросом, или данные, полученные с ответом.
Первая часть каждого HTTP-запроса содержит три элемента:
Когда URL содержит знак «?» это означает, что он содержит запрос. Это означает, что он отправляет параметры запрошенного ресурса.
В HTTP-запросе есть и другие интересные вещи:
Referer header — сообщает URL-адрес, с которого поступил запрос.
User-Agent header — дополнительная информация об используемом браузере.
Host header — показывает имя хоста. Его следует уникально идентифицировать, это необходимо, когда несколько веб-страниц размещаются на одном сервере.
Cookie header — отправляет дополнительные параметры на клиент.
HTTP-ответы
Как и HTTP-запросы, HTTP-ответы состоят из трех элементов:
Например: _HTTP/1.1 200 OK_
В HTTP-ответе есть и другие интересные вещи: Server header — показывает программное обеспечение сервера.
Set-Cookie header — используется для создания cookie в браузере.
Message body — обычно HTTP-ответ содержит тело сообщения.
Content-Length header — сообщает размер тела сообщения в байтах.
HTTP-методы
Наиболее распространёнными методами являются GET и POST, но бывают и другие.
GET — используется для запросы данных с определенного ресурса, на котором данные не изменяются, поскольку GET-запросы не изменяют состояние ресурса.
POST — используется для отправки данных на сервер для создания ресурса.
PUT — метод для обновления существующего на сервере ресурса, используя содержимое тела запроса.
HEAD — этот метод выполняет ту же функцию, что и GET-метод, но с той разницей, что HEAD не содержит тело запроса. Но он вернёт те же заголовки, что и метод GET. Метод HEAD используют для проверки существования ресурса, перед выполнением метода GET.
TRACE — метод предназначен для диагностических целей. Ответ будет содержать в своем теле точное содержание запроса.
OPTIONS — этот метод используется для описания параметров связи (методов HTTP), доступных для целевого ресурса.
PATCH — используется для применения частичных модификаций к ресурсу..
DELETE — удаляет определённый ресурс.
Передача репрезентативного состояния (REST) — это стиль архитектуры, в котором запрос и ответы содержат представление текущего состояния системного ресурса.
Я буду говорить больше о REST API в других статьях, следите за новостями.
HTTP-заголовки
Струтура запроса/ответа состоит из трёх частей:
Мы уже говорили о первой строке в HTTP-запросах и ответах, упоминали тело, а теперь поговорим о HTTP-заголовках.
HTTP-заголовки добавляются после первой строки и определяются как пары _имя:значение_, разделённые двоеточием. HTTP-заголовки используются для отправки дополнительных параметров вместе с запросом или ответом. Как мы уже говорили, тело сообщения содержит данные, которые будут отправлены вместе с запросом, или данные, полученные вместе с ответом.
Существуют различные типы заголовков, которые мы группируем на основе их использования в 4 широких категорий:
General header (Главные заголовки) — могут использоваться для всех типов сообщений (запроса и ответа) и независимы от передаваемых данных.
Request header (Заголовки запроса) — определяют параметры для запрашиваемых данных или параметры с важной информацией о клиенте, совершающем запрос.
Response header (Заголовки ответа) — содержат информацию об ответе
Entity header (Заголовки сущностей) — описывают содержимое, которое составляет тело сообщения.
HTTP-коды ответов
Каждый HTTP-ответ должен содержать код состояния HTTP, сообщающий результат запроса.
Существует пять групп кодов состояния. Их группируют по первой цифре:
HTTPS (Hypertext Transfer Protocol Secure)
Безопасной версией протокола HTTP является HyperText Transfer Protocol Secure — защищённый протокол передачи гипертекста (HTTPS). HTTPS обеспечивает шифрованную связь между браузером (клиентом) и веб-сайтом (сервером).
В HTTPS протокол связи шифруется с использованием безопасности транспортного уровня (TLS) или уровня защищенных сокетов (SSL).
Также протокол часто называют HTTP поверх TLS или HTTP поверх SSL.
Оба протокола TLS и SSL используют систему асимметричного шифрования. Система асимметричного шифрования использует открытый ключ (ключ шифрования) и закрытый ключ (ключи дешифрования) для шифрования сообщения. Любой может использовать открытый ключ для шифрования сообщения. Однако закрытые ключи являются секретными, и это означает, что только предполагаемый получатель может расшифровать сообщение.
SSL/TLS handshake
При запросе HTTPS-соединения с сайтом, сайт отправляет свой SSL-сертификат вашему браузеру. Этот процесс, когда ваш браузер и веб-сайт инициируют связь, называется «SSL/TLS handshake».
SSL/TLS handshake включает в себя ряд шагов, когда браузер и веб-сайт проверяют друг друга и начинают связь через туннель SSL/TLS.
Можно заметить, что во время соединения HTTPS используется надежный защищённый туннель и в адресной строке браузера отображается зеленый значок замка.