Перейти к основному содержимому

2.09. HTTP

Всем

HTTP

Структура HTTP-запроса

HTTP-запрос состоит из трёх частей - стартовая строка, заголовок и тело запроса.

Стартовая строка указывает метод, путь и версию протокола. Пример:

GET /posts/1 HTTP/1.1

Стартовая строка - это самая первая строка запроса, которая формируется по шаблону:

<Метод> <Путь> <Версия протокола>

Методом называется действие, которое хочет выполнить клиент (GET, POST, PUT, PATCH, DELETE и другие).

Путь - это URL-адрес на сервере, указывающий, к какому ресурсу обращается клиент.

Версия протокола - это версия HTTP, которую использует клиент (HTTP/1.1, HTTP/2, HTTP/3).

Заголовок содержит дополнительную информацию о запросе. Это блок метаданных, передаваемых вместе с запросом. Заголовки содержат информацию о клиенте, теле запроса, авторизации, формате данных и многое другое.

Заголовок формируется по формату:

<Имя заголовка>: <Значение>

Заголовки бывают общие, кастомные, заголовки запроса и заголовки сущности. Мы отдельно их рассмотрим.

Тело запроса является необязательным и используется для методов POST, PUT, PATCH. Тело содержит полезные данные, отправляемые серверу. К примеру, JSON:

{
"title": "foo",
"body": "bar",
"userId": 1
}

Формат данных в теле определяется через заголовок Content-Type, HTTP-заголовок, который указывает тип содержимого в теле запроса или ответа. Пример:

Content-Type: text/html; charset=UTF-8

Это означает, что тело сообщения содержит HTML-документ, использующий кодировку UTF-8. А для JSON указывается application/json. Важно понимать, что путь в запросах представляет собой часть URI после домена, которая указывает на конкретный ресурс. К примеру, если Host указан как api.example.com, а в стартовой строке указан путь как /api/users, то полный URI будет http://api.example.com/api/users. Мы же помним разницу между URL и URI?

Пути могут содержать:

  • параметры пути - /users/123
  • параметры строки запроса (или просто параметры запроса) - ?sort=date&limit=10

Учитывая всю эту кучу информации, нам понадобится шаблон для составления сложных запросов, который бы включал все ключевые элементы:

<МЕТОД> <ПУТЬ> <ВЕРСИЯ ПРОТОКОЛА>
Host: <ХОСТ>
[ЗАГОЛОВОК 1]: <ЗНАЧЕНИЕ 1>
[ЗАГОЛОВОК 2]: <ЗНАЧЕНИЕ 2>
...
[ЗАГОЛОВОК N]: <ЗНАЧЕНИЕ N>

<ТЕЛО ЗАПРОСА (необязательно)>

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

Для простоты лучше использовать Postman и curl - они автоматически добавляют нужные заголовки и корректно формируют тело.

Когда и какие версии HTTP использовать?

HTTP/0.9 - простая версия 1991 года выпуска. Это очень простой протокол, там есть только GET, без заголовков и статус-кодов.

HTTP/1.0 выпущена в 1996 году, туда как раз и были добавлены заголовки, коды состояния и MIME-типы.

HTTP/1.1 выпущен в 1999 году и используется до сих пор. Здесь добавили поддержку keep-alive (persistent connections), pipelining, хостинга на одном IP.

Keep-Alive — это механизм, позволяющий повторно использовать одно TCP-соединение для нескольких HTTP-запросов и ответов. Просто добавляется заголовок Connection: keep-alive. Если он не указан, в HTTP/1.1 добавляется по умолчанию, чтобы его отключить надо указать close. Это уменьшает задержку, связанную с установкой новых TCP-соединений, ускоряет загрузку страницы за счёт повторного использования соединения, и экономит ресурсы сервера.

Pipelining — возможность отправки нескольких HTTP-запросов подряд по одному соединению без ожидания ответа на предыдущий, что ускоряет работу клиент-серверного взаимодействия. Но не все серверы его поддерживают, и требуется строгое соблюдение порядка ответов, при работе с прокси или брандмауэрами могут быть проблемы. В HTTP/2 pipelining заменён более мощным механизмом — мультиплексированием.

HTTP/2 появился в 2015, добавив бинарный протокол, мультиплексирование, сжатие заголовков, сервер push. В отличие от текстового формата HTTP/1.x, в HTTP/2 используется бинарный формат передачи данных, что позволяет более эффективно парсить данные, уменьшает вероятность ошибок при чтении запросов и ответов, а также использовать новые функции, такие как потоки и мультиплексирование.

Мультиплексирование - одна из ключевых особенностей HTTP/2, когда клиент может отправлять несколько запросов по одному TCP-соединению, не дожидаясь ответа на предыдущий. Это устраняет проблему последовательной загрузки ресурсов, снижает задержку (latency) и позволяет браузеру быстрее загружать страницы.

Заголовки часто повторяются между запросами. В HTTP/2 используется сжатие заголовков через алгоритм HPACK, который снижает объём данных, особенно при множестве небольших запросов.

Сервер Push подразумевает, что сервер может предварительно отправить клиенту ресурсы, которые он ещё не запрашивал, но, возможно, потребуется в будущем (например, CSS или JS).

HTTP/3 выпущен в 2022, работает поверх UDP через QUIC, устраняет head-of-line blocking. Если проще, протокол QUIC использует UDP вместо TCP, что обеспечивает быстрое восстановление соединений при смене сети (например, с Wi-Fi на мобильную сеть), обеспечивать шифрование по умолчанию. А устранение head-of-line blocking подразумевает, что если одно сообщение теряется, это не блокирует все остальные.

Пример сложного HTTP-запроса:

PATCH /api/v2/users/12345/preferences HTTP/2
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx
Content-Type: application/json
Accept: application/vnd.mycompany.api.v2+json
Accept-Language: en-US,en;q=0.9,ru;q=0.8
If-Match: "a1b2c3d4"
X-Request-ID: 7c6d3a1b-9f0e-4d2a-bcde-f123456789ab
Cache-Control: no-cache

{
"theme": "dark",
"notifications": {
"email": true,
"sms": false
},
"preferences": {
"language": "en",
"currency": "USD",
"units": "metric"
},
"favorite_items": [101, 102, 105]
}

Давайте разберём.

  1. Стартовая строка здесь будет такой:
PATCH /api/v2/users/12345/preferences HTTP/2

PATCH - метод, используется для частичного обновления ресурса.

/api/v2/users/12345/preferences — путь к ресурсу на сервере.

HTTP/2 — версия протокола. В отличие от HTTP/1.1, это бинарный протокол с поддержкой мультиплексирования.

  1. Заголовок здесь будет часть запроса, от Host до Cache-Control.

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

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx - это токен авторизации в формате JWT (JSON Web Token). Используется для идентификации пользователя или сервиса.

Content-Type: application/json указывает, что тело запроса содержит данные в формате JSON.

Accept: application/vnd.mycompany.api.v2+json это запрашиваемый формат ответа. Здесь указан кастомный MIME-тип для API версии 2 от компании mycompany.

Accept-Language: en-US,en;q=0.9,ru;q=0.8 это языковые предпочтения клиента. Сервер может выбрать язык ответа в зависимости от доступных вариантов.

If-Match: "a1b2c3d4" это условный заголовок. Сервер выполнит запрос только если ETag ресурса совпадает с этим значением. Используется для оптимистической блокировки (preventing race conditions).

X-Request-ID: 7c6d3a1b-9f0e-4d2a-bcde-f123456789ab это кастомный заголовок, используемый для логгирования и трассировки запроса на стороне сервера.

Cache-Control: no-cache это инструкция клиенту и промежуточным серверам не использовать закэшированный ответ без проверки актуальности.

  1. Тело запроса здесь будет JSON-объектом, содержащим пользовательские настройки интерфейса (тема), уведомления - включены ли email или SMS, предпочтения (язык, валюта, единицы измерения), список любимых элементов (ID товаров).

Приведенный в примере запрос является сложным, так как здесь используется редкий метод PATCH, версия HTTP/2 (бинарный протокол, мультиплексирование и другие продвинутые возможности), авторизация через Bearer Token, кастомный Accept тип и условный запрос.

Bearer Token это механизм авторизации, при котором клиент предоставляет токен (к примеру, через OAuth2 или JWT), который сервер проверяет. При каждом запросе к защищённому API клиент добавляет заголовок Authorization. Сервер проверяет токен и, если он действителен, разрешает доступ. Кастомные заголовки и типы обычно начинаются с префикса X-… - хотя с 2012 года рекомендуется использовать зарегистрированные заголовки , а не X-*, так как некоторые системы могут игнорировать такие заголовки. Кастомные типы контента (MIME-типы) указываются без X, но, как выше приведено в примере, может указывать на специфический формат (application/vnd.mycompany.api.v2+json - JSON в специальной версии v2 от компании mycompany).

Условные запросы в HTTP представляют собой механизм, позволяющий выполнять запросы только при выполнении определённых условий.

ЗаголовокНазначение
If-MatchВыполнить запрос, только если ETag совпадает.
If-None-MatchВыполнить запрос, только если ETag НЕ совпадает.
If-Modified-SinceТолько если ресурс был изменён после указанной даты.
If-RangeИспользуется при частичной загрузке (Range requests).

Условные запросы могут предотвратить конфликты при параллельном редактировании, экономят трафик (например, не отправляют данные, если клиент уже имеет актуальную версию), позволяют организовать кэширование и частичную синхронизацию. E-Tag - это уникальный идентификатор текущей версии ресурса.

Структура HTTP-ответа

HTTP-ответ содержит тоже три составные части - статус-строка, заголовки и тело ответа.

Статус-строка содержит версию протокола, статусный код и фразу (например, 200 OK). К примеру:

HTTP/2 200 OK

Заголовки содержат метаданные ответа.

Тело ответа содержит фактические данные, например, HTML-страница или данные в JSON.

Пример сложного ответа от сервера:

HTTP/2 200 OK
Content-Type: application/vnd.mycompany.api.v2+json
Content-Language: en-US
ETag: "z9y8x7w6"
X-Request-ID: 7c6d3a1b-9f0e-4d2a-bcde-f123456789ab
Cache-Control: no-store
Vary: Accept-Encoding, Accept-Language
Server: MyCompany-API-Gateway
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
"status": "success",
"message": "Preferences updated successfully",
"data": {
"user_id": 12345,
"theme": "dark",
"notifications": {
"email": true,
"sms": false
},
"preferences": {
"language": "en",
"currency": "USD",
"units": "metric"
},
"favorite_items": [101, 102, 105],
"updated_at": "2025-04-05T14:30:00Z"
},
"meta": {
"version": "v2",
"server_time": "2025-04-05T14:30:00Z",
"request_id": "7c6d3a1b-9f0e-4d2a-bcde-f123456789ab"
}
}

Здесь в статус-строке указана версия протокола HTTP/2, код успешного выполнения запроса (200) и ОК - фраза, описывающая результат. В данном случае сервер успешно обработал PATCH-запрос и обновил часть данных пользователя.

Content-Type указывает, что формат данных в теле ответа: application/vnd.mycompany.api.v2+json — специальная версия API компании. Content-Language говорит, что язык содержимого en-US.

ETag это специальный тег, который является уникальным идентификатором текущей версии ресурса. Используется для условных запросов (If-Match, If-None-Match).

X-Request-ID имеет тот же ID, что был отправлен клиентом — используется для логгирования и трассировки.

Cache-Control: no-store говорит о том, что сервер запрещает сохранять этот ответ в кэше.

Vary говорит прокси-серверам, какие заголовки влияют на выбор правильного ответа. Здесь учитываются Accept-Encoding и Accept-Language. Server содержит информацию о сервере.

Strict-Transport-Security обязывает браузер использовать HTTPS, защищая от downgrade-атак.

X-Content-Type-Options: nosniff запрещает браузеру пытаться угадать MIME-тип.

X-Frame-Options: DENY защищает от clickjacking-атак, запрещая отображать страницу в <iframe>. Мы же помним, что такое iframe?

С телом ответа проще - тут JSON, который содержит общий статус операции, сообщение, данные, метаданные.

HTTP-заголовки

Давайте рассмотрим HTTP-заголовки.

  1. Общие заголовки (General Headers). Заголовки, которые относятся к всему сообщению, но не связаны ни с запросом, ни с ответом напрямую.
ЗаголовокОписание
Cache-ControlУправление кэшированием
ConnectionУправление сетевым соединением (keep-alive, close)
DateДата и время создания сообщения
PragmaСовместимость с устаревшими кэшами
TrailerУказывает, какие заголовки будут отправлены после тела сообщения
Transfer-EncodingСпособ кодирования передачи тела сообщения (например, chunked)
UpgradeПредложение переключиться на другую версию протокола
ViaИспользуется прокси для указания пути
WarningИнформация о проблемах при обработке сообщения
  1. Заголовки запроса (Request Headers). Передаются клиентом (браузером) серверу и содержат информацию о самом запросе, клиенте или желаемом ответе.
ЗаголовокОписание
AcceptКакие типы контента клиент может обработать
Accept-CharsetПоддерживаемые клиентом кодировки
Accept-EncodingПоддерживаемые методы сжатия (gzip, deflate)
Accept-LanguageЯзыковые предпочтения клиента
AuthorizationДанные аутентификации
CookieКлиентские cookies
ExpectОжидание определённого ответа от сервера
FromEmail пользователя (редко используется)
HostИмя хоста (обязательный заголовок в HTTP/1.1)
If-Match, If-None-MatchУсловные запросы
If-Modified-SinceПроверка изменения ресурса
Max-ForwardsОграничение числа прыжков через прокси
Proxy-AuthorizationАвторизация перед прокси
RangeЗапрос части ресурса
RefererОткуда был сделан запрос
TEКакие расширения передачи поддерживает клиент
User-AgentИнформация о браузере и ОС
  1. Заголовки ответа (Response Headers). Устанавливаются сервером и содержат информацию о результате выполнения запроса.
ЗаголовокОписание
Accept-RangesПоддерживаемые диапазоны (например, bytes)
AgeВозраст ответа (сколько секунд прошло с момента его генерации)
Content-TypeФормат данных в теле ответа.
Content-LanguageЯзык содержимого.
ETagУникальный идентификатор версии ресурса. Используется для условных запросов (If-Match, If-None-Match).
LocationАдрес нового ресурса (часто в ответах 3xx)
Proxy-AuthenticateМетод аутентификации перед прокси
Retry-AfterКогда клиент может повторить запрос
ServerИнформация о сервере или шлюзе, который обработал запрос.
Set-CookieУстановка cookie на стороне клиента
Strict-Transport-SecurityОбязывает браузер использовать HTTPS, защищая от downgrade-атак.
WWW-AuthenticateТребование авторизации
VaryКакие заголовки влияют на выбор закэшированной версии ответа. Здесь учитываются Accept-Encoding и Accept-Language.
  1. Заголовки сущности (Entity Headers). Описывают тело сообщения (его тип, размер, кодировку и т. д.).
ЗаголовокОписание
AllowПоддерживаемые методы
Content-EncodingСпособ кодирования тела (gzip, compress)
Content-LanguageЯзык содержимого
Content-LengthРазмер тела сообщения в байтах
Content-LocationАльтернативное расположение ресурса
Content-MD5Контрольная сумма тела (устарел)
Content-RangeДиапазон передаваемых данных
Content-TypeMIME-тип тела сообщения
Content-DispositionКак браузер должен обрабатывать содержимое (например, inline отобразит в браузере, а attachment предложит сохранить)
ExpiresДата истечения срока действия кэша
Last-ModifiedДата последнего изменения ресурса

Content-Type состоит из типа (type) и подтипа (subtype), разделённых косой чертой (type/subtype). Их называют MIME-типы (Multipurpose Internet Mail Extensions), это типы данных, которые могут быть переданы через сеть.

К примеру - text/plain, image/jpeg, application/json. Иногда добавляются парамтеры, например, charset=utf-8, boundary=something_unique.

Есть чит-лист с MIME-типами - https://cheatsheets.zip/mime

Основные категории Content-Type:

  1. text/ — текстовые данные, простой текст:
ТипОписание
text/plainОбычный текст без форматирования
text/htmlHTML-документ
text/cssCSS-стили
text/javascriptJavaScript-код (устаревший, сейчас чаще используется application/javascript)
text/csvТаблицы в формате CSV
  1. image/ — графические изображения:
ТипОписание
image/jpegФотографии, формат JPEG
image/pngИзображения с прозрачностью, PNG
image/gifАнимированные/статичные GIF
image/webpСовременный формат от Google
image/svg+xmlВекторная графика в формате SVG
  1. audio/ и video/ — медиафайлы
ТипОписание
audio/mpegMP3-файл
audio/oggOGG-формат аудио
video/mp4Видео в формате MP4
video/webmВидео WebM, поддерживается в браузерах
  1. application/ — прикладные данные, это самый обширный тип, используется для файлов, данных в определённом формате, двоичных данных и т. д.:
ТипОписание
application/jsonJSON-данные
application/xmlXML-данные
application/javascriptJavaScript документ
application/soap+xmlSOAP
application/xhtml+xmlXHTML документ
application/pdfPDF-документ
application/mswordДокумент Word (.doc)
application/vnd.openxmlformats-officedocument.wordprocessingml.documentWord .docx
application/octet-streamБинарные данные (универсальный «неизвестный» тип)
application/x-www-form-urlencodedДанные формы, отправленной через POST
application/zipZIP-архив
application/gzipGZIP-архив
  1. multipart/ — составные сообщения, используемые, когда в одном сообщении передаётся несколько частей. Например, при загрузке файла через форму. Виды:
ТипОписание
multipart/form-dataИспользуется при загрузке файлов через HTML-формы
multipart/byterangesИспользуется для передачи диапазонов байтов (например, при паузе в загрузке)
  1. message/ — сообщения:
ТипОписание
message/rfc822Сообщение электронной почты в формате RFC 822
message/httpСообщение HTTP внутри другого HTTP-сообщения
  1. model/ — моделирование: | Тип | Описание | | :--- | :---: | |model/stl |STL-файлы 3D-моделей |model/gltf+json |Формат GLTF для 3D-графики

Content-Type отсутствует, если данные передаются в URL. Такое можно наблюдать в запросах с методом GET. К примеру, здесь нет Content-Type, так как нет данных в теле:

GET /search?q=hello HTTP/1.1
Host: example.com

Основной способ отправки данных - метод POST:

POST /api/login HTTP/1.1
Content-Type: application/json
Content-Length: 45

{"username":"john","password":"secret"}

Здесь указывается метод POST, URL api/login, протокол HTTP/1.1, тип контента же представляет собой JSON-объект.

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

HTTP-методы

HTTP-методы определяют тип действия, которое клиент хочет выполнить на сервере. Основые методы:

МетодОписание
GETПолучить данные. Запрос данных с сервера (например, получить HTML-страницу или JSON-данные).
HEADАналог GET, но сервер возвращает только заголовки, без тела ответа.
POSTОтправка данных на сервер для создания нового ресурса или выполнения действия.
PUTОбновление существующего ресурса на сервере.
DELETEУдаление ресурса на сервере.
OPTIONSПолучить поддерживаемые методы. Запрос информации о доступных методах и возможностях сервера (например, CORS).
PATCHЧастичное обновление ресурса (в отличие от PUT, который заменяет весь ресурс). Изменяются только указанные поля, допустим лишь часть указанную в JSON.
CONNECTИспользуется для HTTPS-туннелирования
TRACEДиагностический метод для отладки

HTTP-статусы

HTTP-статусы указывают на результат выполнения запроса. Они делятся на группы:

  1. 1xx — Информационные:
    • 100 Continue — Сервер получил заголовки запроса и ожидает продолжения.
    • 101 Switching Protocols — Сервер согласился сменить протокол (например, на WebSocket).
  2. 2xx — Успешные:
    • 200 OK — Запрос выполнен успешно.
    • 201 Created — Ресурс успешно создан (обычно после POST).
    • 204 No Content — Запрос выполнен, но ответ не содержит тела.
  3. 3xx — Перенаправления:
    • 301 Moved Permanently — Ресурс перемещён на новый URL.
    • 302 Found — Временное перенаправление.
    • 304 Not Modified — Ресурс не изменился с момента последнего запроса.
  4. 4xx — Ошибки клиента:
    • 400 Bad Request — Некорректный запрос.
    • 401 Unauthorized — Необходима аутентификация.
    • 403 Forbidden — Доступ запрещён.
    • 404 Not Found — Ресурс не найден.
    • 429 Too Many Requests — Превышено количество запросов.
  5. 5xx — Ошибки сервера:
    • 500 Internal Server Error — Внутренняя ошибка сервера.
    • 502 Bad Gateway — Неправильный ответ от вышестоящего сервера.
    • 503 Service Unavailable — Сервер временно недоступен.

Чит-лист с HTTP-кодами - https://cheatsheets.zip/http-status-code