Зарегистрируйтесь, чтобы продолжить обучение

Тело HTTP-запроса Протокол HTTP

HTTP request и response могут содержать так называемое тело (body).

Структура и тело запроса

Мы уже знаем, что сам HTTP-запрос состоит из заголовков и опционального тела запроса. Для отделения заголовков от тела существуют определенные правила. Давайте посмотрим на примере, как работать с body и каким образом посылать какие-то данные кроме заголовков. Сделаем HTTP-запрос к хосту http.hexlet.app:

telnet http.hexlet.app 80

Trying 188.114.97.0...
Connected to http.hexlet.app.
Escape character is '^]'.
GET /http-protocol/tasks HTTP/1.1
HOST: http.hexlet.app

HTTP/1.1 200 OK
Date: Wed, 02 Oct 2024 10:46:30 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 1105
Connection: keep-alive
CF-Cache-Status: DYNAMIC
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=u3sdx2IpksLSErg9j3TWyTFIPfJq9mDJxdKklS7WmFjmjUkVEeH4GCbdKWf1qrbej7RGXz%2BxTuiGFE39qHGMFvtFTU0EOvlh1In2M77JhbDHRtuxbwWkx8NiAQIp%2F8hMykE%3D"}],"group":"cf-nel","max_age":604800}
NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 8cc41be28d911108-HKG

{"tasks":[{"id":"1","title":"Опубликовать курс по основам JavaScript","description":"Автор подготовил курс по JavaScript. Нужно его опубликовать","status":"Backlog"},{"id":"2","title":"Опубликовать курс по основам Ruby","description":"Автор подготовил курс по Ruby. Нужно его опубликовать","status":"Ready"},{"id":"3","title":"Опубликовать курс по основам PHP","description":"Автор подготовил курс по PHP. Нужно его опубликовать","status":"In Progress"},{"id":"4","title":"Опубликовать курс по основам Java","description":"Автор подготовил курс по Java. Нужно его опубликовать","status":"Done"},{"id":"5","title":"Опубликовать курс по основам Python","description":"Автор подготовил курс по Python. Нужно его опубликовать","status":"Archived"}],"total":5,"skip":0,"limit":30}

В ответ мы получаем какие-то заголовки и далее идет тело, которое нас как раз и интересует. В данном случае это список задач.

Если с заголовками все понятно, они отделяются друг от друга переводом строки и для отправки мы добавляем еще один перевод, который выглядит как пустая строка, то как быть с телом запроса? Оно может содержать внутри все что угодно. Мы не можем кодировать перевод строки как специальный символ. Ведь те самые два перевода строки могут находиться внутри тела запроса. Но существуют и другие причины, по которым в текстовом протоколе нельзя просто так определить когда заканчивается тело. Если бы мы приняли ответ при отсутствии каких-то специальных механизмов, то после того как сервер отправил первые два перевода строки мы сразу увидели бы ответ и все что посылалось дальше вообще не считалось бы частью ответа HTTP response. Для решения этой проблемы был придуман другой, более универсальный механизм. Он основан на передаче специального заголовка.

Во время отправки ответа сервер формирует специальный заголовок, который называется Content-Length. Это и есть ключ к тому как работать с body. Перед тем как отправить тело ответа, происходит вычисление его длины и записывается количество байт.

# число — количество байт
Content-Length: 1105

После того как передан такой заголовок, другая сторона будет ожидать ровно столько байт, сколько в нем указано. Как мы помним, для response и request это работает абсолютно одинаково. После того как был передан последний символ, соединение закрывается. Стоит уточнить, что закрывается именно HTTP-сессия. На сервере может быть активен keep-alive, но ключевой момент в том, что запрос считается завершенным и отображается.

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

Практика показывает, что не все серверы правильно работают при наличии только заголовка Content-Length. Им не хватает еще одного. Тип содержимого запроса или ответа, которое содержит body, должен быть как-то идентифицирован. По умолчанию в стандарте сказано, что сервер может сам попытаться определить содержимое контента на основе различных способов. Например, мы в query string делаем запрос tasks.

POST /http-protocol/tasks HTTP/1.1

Совсем не обязательно, но сервер может понять, что это JSON, и как-то это использовать. Во всех остальных случаях, когда сервер не может определить тип контента, он должен использовать заголовок Content-Type: application/octet-stream. Это означает, что в теле запроса передается просто поток байтов. Хотя серверы должны работать именно так, но часто все происходит по-другому. Если указан только Content-Length, то сервер отказывается принимать данные. Он просто закрывает соединение после двух переводов строки, еще до body. Этот нюанс выяснен экспериментальным путем.

Еще одно замечание по поводу body. С точки зрения стандарта HTTP тело может присутствовать в любом запросе и никак не связано с глаголом. Посылать body можно в HEAD, POST, PUT и других запросах. Если мы посылаем body с GET, хотя это не описано в стандарте, сервер никак не будет на это реагировать, более того, он и не должен, так как с практической точки зрения это не имеет смысла. Также есть типы запросов, при которых он не будет посылать в ответ body ни в коем случае. Например, ответ на HEAD, когда мы запрашиваем только заголовки, так как такова семантика этого глагола. Еще тело не отправляется, когда мы получаем в ответ такие статусы как 204 — нет контента и некоторые другие.


Дополнительные материалы

  1. Википедия / Тело сообщения
  2. Формат HTTP-запросов
  3. Формат HTTP-ответов

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

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

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 25 000 ₸ в месяц
Разработка фронтенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 26 декабря
профессия
от 25 000 ₸ в месяц
Разработка веб-приложений на Django
10 месяцев
с нуля
Старт 26 декабря
профессия
от 14 960 ₸ в месяц
Ручное тестирование веб-приложений
4 месяца
с нуля
Старт 26 декабря
профессия
от 25 000 ₸ в месяц
Разработка приложений на языке Java
10 месяцев
с нуля
Старт 26 декабря
профессия
от 25 000 ₸ в месяц
Разработка веб-приложений на Laravel
10 месяцев
с нуля
Старт 26 декабря
профессия
от 39 525 ₸ в месяц
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
16 месяцев
с нуля
Старт 26 декабря
профессия
от 25 000 ₸ в месяц
Разработка бэкенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 26 декабря
профессия
новый
Автоматизированное тестирование веб-приложений на JavaScript
8 месяцев
c опытом
Старт 26 декабря

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»