Сообщения
Сообщения HTTP
Сообщения HTTP — это механизм обмена данными между сервером и клиентом в протоколе HTTP. Существует два типа сообщений: запросы, отправляемые клиентом для запуска действия на сервере, и ответы — ответ сервера на запрос.
Разработчики редко, если вообще когда-либо, создают сообщения HTTP с нуля. Такие приложения, как браузер, прокси-сервер или веб-сервер, используют программное обеспечение, предназначенное для надёжного и эффективного создания сообщений HTTP. Способы создания и преобразования сообщений определяются с помощью API в браузерах, файлов конфигурации прокси-серверов или серверов либо других интерфейсов.
В версиях протокола HTTP вплоть до HTTP/2 сообщения представлены в текстовом формате, и их относительно легко читать и понимать после знакомства с форматом. В HTTP/2 сообщения заключены в бинарные кадры, из-за чего читать их немного сложнее. Однако семантика протокола остаётся неизменной, поэтому вы можете изучить структуру и значение сообщений HTTP на примере текстового формата сообщений HTTP/1.x и применить эти знания к HTTP/2 и более поздним версиям.
В этом руководстве для наглядности используются сообщения HTTP/1.1, а структура сообщений HTTP описывается в формате HTTP/1.1. В заключительном разделе мы отметим некоторые различия, которые могут понадобиться для описания HTTP/2.
Примечание: Сообщения HTTP можно просматривать на вкладке Сеть в инструментах разработчика браузера или, например, выводить в консоль с помощью инструментов командной строки, таких как curl.
Структура сообщения HTTP
Чтобы понять, как работают сообщения HTTP, рассмотрим сообщения HTTP/1.1 и изучим их структуру. На следующей иллюстрации показано, как выглядят сообщения HTTP/1.1:
Запросы и ответы имеют схожую структуру:
- Стартовая строка — это одна строка, описывающая версию HTTP, а также метод запроса или результат запроса.
- Необязательный набор заголовков HTTP, содержащих метаданные, описывающие сообщение. Например, запрос ресурса может указывать допустимые форматы этого ресурса, а в ответе могут быть заголовки, указывающие фактический возвращённый формат.
- Пустая строка, указывающая, что метаданные сообщения завершены.
- Необязательное тело, содержащее данные, связанные с сообщением. Это могут быть данные POST, отправляемые серверу в запросе, или ресурс, возвращаемый клиенту в ответе. Наличие тела в сообщении определяется стартовой строкой и заголовками HTTP.
Стартовая строка и заголовки сообщения HTTP вместе называются заголовком запроса, а следующая за ними часть, содержащая его содержимое, называется телом.
Запросы HTTP
Рассмотрим следующий пример запроса HTTP POST, который отправляется после того, как пользователь отправляет форму на веб-странице:
POST /users HTTP/1.1 Host: example.com Content-Type: application/x-www-form-urlencoded Content-Length: 49 name=FirstName+LastName&email=bsmth%40example.com
Стартовая строка в запросах HTTP/1.x (POST /users HTTP/1.1 в примере выше) называется «строкой запроса» и состоит из трёх частей:
<method> <request-target> <protocol>
<method>-
Метод HTTP (также называемый глаголом HTTP) — это одно из набора определённых слов, описывающих смысл запроса и желаемый результат. Например,
GETуказывает, что клиент хочет получить ресурс в ответ, аPOSTозначает, что клиент отправляет данные на сервер. <request-target>-
Цель запроса обычно представляет собой абсолютный или относительный URL и определяется контекстом запроса. Формат цели запроса зависит от используемого метода HTTP и контекста запроса. Более подробно это описано в разделе Цели запросов ниже.
<protocol>-
Версия HTTP, определяющая структуру оставшейся части сообщения и указывающая версию, которую следует использовать для ответа. Почти всегда это
HTTP/1.1, посколькуHTTP/0.9иHTTP/1.0устарели. В HTTP/2 и более поздних версиях версия протокола не включается в сообщения, так как определяется при установлении соединения.
Цели запросов
Цель запроса можно описать несколькими способами, но наиболее распространённая форма — «origin form». Ниже перечислены типы целей и случаи их использования:
-
В origin form получатель объединяет абсолютный путь с информацией из заголовка
Host. К пути можно добавить строку запроса с дополнительной информацией (обычно в форматеkey=value). Эта форма используется с методамиGET,POST,HEADиOPTIONS:GET /en-US/docs/Web/HTTP/Guides/Messages HTTP/1.1
-
Абсолютная форма — это полный URL, включая полномочия, и она используется с
GETпри подключении к прокси-серверу:GET https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Messages HTTP/1.1
-
Форма полномочий — это полномочия и порт, разделённые двоеточием (
:). Она используется только с методомCONNECTпри настройке HTTP-туннеля:CONNECT developer.mozilla.org:443 HTTP/1.1
-
Форма со звёздочкой используется только с
OPTIONS, когда нужно представить сервер целиком (*), а не именованный ресурс:OPTIONS * HTTP/1.1
Заголовки запросов
Заголовки — это метаданные, отправляемые вместе с запросом после стартовой строки и до тела. В приведённом выше примере отправки формы это следующие строки сообщения:
Host: example.com Content-Type: application/x-www-form-urlencoded Content-Length: 49
В HTTP/1.x каждый заголовок — это строка, не зависящая от регистра, за которой следует двоеточие (:) и значение, формат которого зависит от заголовка. Весь заголовок, включая значение, состоит из одной строки. В некоторых случаях эта строка может быть очень длинной, например, у заголовка Cookie.
Некоторые заголовки используются исключительно в запросах, тогда как другие могут отправляться как в запросах, так и в ответах или относиться к более конкретной категории:
- Заголовки запросов предоставляют дополнительный контекст запроса или задают дополнительную логику его обработки сервером (например, условные запросы).
- Заголовки представления отправляются в запросе, если у сообщения есть тело, и описывают исходную форму данных сообщения и применённую кодировку. Это позволяет получателю понять, как восстановить ресурс в том виде, в котором он был до передачи по сети.
Тело запроса
Тело запроса — это часть запроса, содержащая информацию для сервера. Тело есть только у запросов PATCH, POST и PUT. В примере отправки формы эта часть и есть тело:
name=FirstName+LastName&email=bsmth%40example.com
Тело запроса с отправкой формы содержит относительно небольшой объём информации в виде пар key=value, но тело запроса может содержать и другие типы данных, которые ожидает сервер:
{
"firstName": "Brian",
"lastName": "Smith",
"email": "bsmth@example.com",
"more": "data"
}
или данные, состоящие из нескольких частей:
--delimiter123 Content-Disposition: form-data; name="field1" value1 --delimiter123 Content-Disposition: form-data; name="field2"; filename="example.txt" Text file contents --delimiter123--
Ответы HTTP
Ответы — это сообщения HTTP, которые сервер отправляет в ответ на запрос. Ответ сообщает клиенту, чем завершился запрос. Ниже приведён пример ответа HTTP/1.1 на запрос POST, в результате которого был создан новый пользователь:
HTTP/1.1 201 Created
Content-Type: application/json
Location: http://example.com/users/123
{
"message": "New user created",
"user": {
"id": 123,
"firstName": "Example",
"lastName": "Person",
"email": "bsmth@example.com"
}
}
Стартовая строка (HTTP/1.1 201 Created выше) в ответах называется «строкой состояния» и состоит из трёх частей:
<protocol> <status-code> <reason-phrase>
<protocol>-
Версия HTTP сообщения.
<status-code>-
Числовой код состояния, указывающий, был ли запрос выполнен успешно или завершился ошибкой. Распространённые коды состояния:
200,404и302. <reason-phrase>Необязательно-
Необязательный текст после кода состояния — это краткое, исключительно информационное описание состояния, помогающее человеку понять результат запроса. Иногда фраза причины заключается в скобки (например, «201 (Created)»), чтобы показать, что она необязательна.
Заголовки ответов
Заголовки ответов — это метаданные, отправляемые вместе с ответом. В HTTP/1.x каждый заголовок — это строка, не зависящая от регистра, за которой следует двоеточие (:) и значение, формат которого зависит от используемого заголовка.
Как и в запросах, в ответах могут присутствовать самые разные заголовки; они делятся на следующие категории:
-
Заголовки ответов предоставляют дополнительный контекст сообщения или задают дополнительную логику для последующих запросов клиента. Например, такие заголовки, как
Server, содержат информацию о программном обеспечении сервера, аDateуказывает, когда был сформирован ответ. Они также могут содержать сведения о возвращаемом ресурсе, например его тип содержимого (Content-Type) или способ его кэширования (Cache-Control). - Заголовки представления, если у сообщения есть тело, описывают форму данных сообщения и применённую кодировку. Например, один и тот же ресурс может быть представлен в определённом типе медиа, например XML или JSON, локализован для конкретного письменного языка или географического региона и/или сжат либо закодирован иным способом для передачи. Это позволяет получателю понять, как восстановить ресурс в том виде, в котором он был до передачи по сети.
Тело ответа
В большинстве сообщений, отправляемых клиенту в ответ, присутствует тело. При успешном выполнении запроса тело ответа содержит данные, запрошенные клиентом в запросе GET. Если с запросом клиента возникли проблемы, в теле ответа обычно объясняется, почему запрос завершился ошибкой, и указывается, является ли эта ошибка постоянной или временной.
Тела ответов могут быть:
- Содержать один ресурс, определяемый двумя заголовками:
Content-TypeиContent-Length, либо иметь неизвестную длину и передаваться частями с заголовкомTransfer-Encoding, установленным в значениеchunked. - Содержать несколько ресурсов — такие тела состоят из нескольких частей, каждая из которых содержит отдельные данные. Составные тела обычно используются в HTML-формах, но также могут отправляться в ответ на запросы диапазона.
Ответы с кодом состояния, который позволяет ответить на запрос без включения содержимого сообщения, например 201 Created или 204 No Content, не имеют тела.
Сообщения HTTP/2
В HTTP/1.x используются текстовые сообщения, которые легко читать и создавать, но у такого подхода есть несколько недостатков. Тела сообщений можно сжимать с помощью gzip или других алгоритмов сжатия, но не заголовки. Заголовки часто похожи или идентичны в ходе взаимодействия клиента и сервера, но повторяются в последующих сообщениях соединения. Известно множество очень эффективных способов сжатия повторяющегося текста, поэтому значительная экономия пропускной способности остаётся неиспользованной.
В HTTP/1.x также существует проблема, называемая блокировкой начала очереди (HOL): клиент должен дождаться ответа сервера, прежде чем отправить следующий запрос. Конвейеризация HTTP пыталась решить эту проблему, но из-за слабой поддержки и сложности используется редко, и её трудно реализовать правильно. Для параллельной отправки запросов необходимо открыть несколько соединений; установленные и активные соединения эффективнее новых из-за медленного старта TCP.
В HTTP/1.1 для параллельной отправки двух запросов нужно открыть два соединения:
Это означает, что количество ресурсов, которые браузеры могут одновременно загружать и отображать, ограничено; обычно оно не превышает 6 параллельных соединений.
HTTP/2 позволяет одновременно использовать одно TCP-соединение для нескольких запросов и ответов. Для этого сообщения помещаются в бинарные кадры, а запросы и ответы передаются в нумерованном потоке внутри соединения. Кадры данных и заголовков обрабатываются отдельно, что позволяет сжимать заголовки с помощью алгоритма HPACK. Использование одного TCP-соединения для одновременной обработки нескольких запросов называется мультиплексированием.
Запросы не обязательно выполняются последовательно: например, потоку 9 не нужно ждать завершения потока 7. Данные из нескольких потоков обычно чередуются в соединении, поэтому клиент может получать потоки 9 и 7 одновременно. Протокол позволяет задавать приоритет для каждого потока или ресурса. Ресурсы с низким приоритетом занимают меньше полосы пропускания, чем ресурсы с высоким приоритетом, когда передаются по разным потокам; также их можно фактически передавать последовательно в одном соединении, если сначала нужно обработать критически важные ресурсы.
В целом, несмотря на все улучшения и абстракции, добавленные по сравнению с HTTP/1.x, разработчикам практически не нужно менять API, используемые для работы с HTTP/2 вместо HTTP/1.x. Если HTTP/2 поддерживается и браузером, и сервером, он включается и используется автоматически.
Псевдозаголовки
Одно из заметных изменений в сообщениях HTTP/2 — использование псевдозаголовков. Вместо стартовой строки сообщения, применявшейся в HTTP/1.x, HTTP/2 использует специальные поля псевдозаголовков, начинающиеся с :. В запросах используются следующие псевдозаголовки:
-
:method— метод HTTP. -
:scheme— схема целевого URI, обычно HTTP(S). -
:authority— полномочия целевого URI. -
:path— путь и параметры запроса целевого URI.
В ответах используется только один псевдозаголовок — :status, содержащий код ответа.
Чтобы выполнить запрос HTTP/2 и получить example.com, можно использовать nghttp, который выведет запрос в более удобном для чтения виде. Выполнить запрос можно этой командой: параметр -n отбрасывает загруженные данные, а -v включает подробный вывод, показывающий приём и передачу кадров:
nghttp -nv https://www.example.com
Если просмотреть вывод ниже, вы увидите время передачи и приёма каждого кадра:
[ 0.123] <send|recv> <frame-type> <frame-details>
Нет необходимости подробно разбирать этот вывод, но обратите внимание на кадр HEADERS в формате [ 0.123] send HEADERS frame .... В строках после передачи заголовка появятся следующие строки:
[ 0.447] send HEADERS frame ...
...
:method: GET
:path: /
:scheme: https
:authority: www.example.com
accept: */*
accept-encoding: gzip, deflate
user-agent: nghttp2/1.61.0
Если вы уже уверенно работаете с HTTP/1.x, это должно быть вам знакомо; понятия, рассмотренные в предыдущем разделе этого руководства, также применимы. Это бинарный кадр с запросом GET для example.com, преобразованный в удобный для чтения вид с помощью nghttp. Если просмотреть вывод команды дальше, в одном из потоков, полученных от сервера, можно увидеть псевдозаголовок :status:
[ 0.433] recv (stream_id=13) :status: 200 [ 0.433] recv (stream_id=13) content-encoding: gzip [ 0.433] recv (stream_id=13) age: 112721 [ 0.433] recv (stream_id=13) cache-control: max-age=604800 [ 0.433] recv (stream_id=13) content-type: text/html; charset=UTF-8 [ 0.433] recv (stream_id=13) date: Fri, 13 Sep 2024 12:56:07 GMT [ 0.433] recv (stream_id=13) etag: "3147526947+gzip" ...
А если удалить из этого сообщения время и идентификатор потока, оно станет ещё более знакомым:
:status: 200 content-encoding: gzip age: 112721
Подробное рассмотрение кадров сообщений, идентификаторов потоков и управления соединением выходит за рамки этого руководства, но для понимания и отладки сообщений HTTP/2 вам должно быть достаточно знаний и инструментов, описанных в этой статье.
Заключение
В этом руководстве представлен общий обзор структуры сообщений HTTP на примере формата HTTP/1.1. Мы также рассмотрели кадрирование сообщений HTTP/2, которое добавляет уровень между синтаксисом HTTP/1.x и базовым транспортным протоколом, не меняя принципиально семантику HTTP. HTTP/2 был создан для решения проблемы блокировки начала очереди, характерной для HTTP/1.x, благодаря возможности мультиплексирования запросов.
В HTTP/2 осталась одна проблема: хотя на уровне протокола блокировка начала очереди была устранена, узким местом производительности по-прежнему остаётся блокировка начала очереди в TCP (на транспортном уровне). HTTP/3 решает это ограничение, используя QUIC — протокол на основе UDP, а не TCP. Это изменение повышает производительность, сокращает время установления соединения и повышает стабильность в медленных или ненадёжных сетях. В HTTP/3 сохраняется основная семантика HTTP, поэтому такие функции, как методы запросов, коды состояния и заголовки, остаются одинаковыми во всех трёх основных версиях HTTP.
Если вы понимаете семантику HTTP/1.1, у вас уже есть прочная основа для изучения HTTP/2 и HTTP/3. Главное различие заключается в том, как эта семантика реализуется на транспортном уровне. Изучив примеры и понятия из этого руководства, вы будете готовы работать с HTTP, понимать смысл сообщений и то, как приложения используют HTTP для отправки и получения данных.
См. также
- Эволюция HTTP
- Механизм обновления протокола
- Термины глоссария:
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Messages