Протокол HTTP

Главный протокол для браузера.

Время чтения: 7 мин

Кратко

Секция статьи "Кратко"

HTTP был разработан как протокол обмена данными между веб-сервером и веб-браузером. Это протокол прикладного уровня модели OSI, который используется для передачи между клиентом и сервером файлов HTML, CSS, JS, API, картинок, аудио, видео, введённых пользователем данных и прочего. Клиент (веб-браузер) отправляет серверу (веб-серверу) запросы и получает от него ответы. Сервер в рамках протокола HTTP практически всегда занимает пассивную позицию.

Как понять

Секция статьи "Как понять"

Есть три главных объекта, которые обмениваются сообщениями:

  1. Клиент (user agent) — программа, которая отправляет запросы, получает и обрабатывает ответы от имени пользователя на устройстве пользователя, например, браузер.
  2. Сервер (веб-сервер) — программа, которая работает на сервере, принимает и обрабатывает запросы от клиента, а затем отправляет ответы клиенту. Этой программой является веб-сервер.
  3. Прокси (прокси-сервер) — программа, которая работает на сервере, пропускает через себя запросы и ответы и выступает в роли посредника между клиентом и сервером.

На первом этапе клиент устанавливает соединение с сервером с помощью протокола транспортного уровня TCP. Клиент может переиспользовать одно и то же соединение для работы с сервером или создавать его каждый раз. Это зависит от задачи, конфигурации сети и конкретных настроек оборудования. После установки соединения клиент посылает HTTP-сообщение с телом и параметрами запроса. Сервер принимает это сообщение и на основании логики работы бэкенда формирует и отправляет HTTP-сообщение ответа.

Схема общения клиента и сервера в контексте HTTP

Протокол HTTP не хранит состояние, поэтому количество соединений не приводит к существенному усложнению взаимодействия между объектами системы. Однако существует понятие сессии, с помощью которой можно передавать и хранить необходимые данные, относящиеся к конкретному сеансу связи. Данные сессии сохраняются на клиенте и на сервере. Например, доступен идентификатор сессии, который позволяет не проводить авторизацию клиента при каждом обращении к серверу.

Прокси-серверы осуществляют сервисные функции:

  • Кэшировать данные запроса или ответа для улучшения производительности и снижения сетевого трафика.
  • Фильтровать данные. Например, можно сканировать данные антивирусом или использовать родительский контроль.
  • Осуществлять балансировку нагрузки, распределяя запросы между разными серверами.
  • Проводить аутентификацию клиентов для управления доступом к ресурсам.
  • Хранить информацию о запросах клиентов и ответах сервера, реализуя таким образом логирование.
  • Обнаруживать некоторые типы атак на сетевой узел (например, определение подозрительного трафика или DDoS-атаки).

Формат сообщения

Секция статьи "Формат сообщения"

HTTP-сообщение представляет собой обычный текст. Структура сообщения строго определена:

  1. Стартовая строка;
  2. Заголовки, передают сервисную информацию;
  3. Тело сообщения, представляет данные в текстовом виде.

Тело сообщения — это опциональная часть сообщения, которая может отсутствовать. Например, для некоторых GET-запросов (то есть запросов со стороны клиента, в качестве метода получения данных для которого выбран метод GET) или для всех HEAD-запросов. Если тело сообщения присутствует, то это обозначается заголовками Content-Length или Transfer-Encoding.

Стартовая строка

Секция статьи "Стартовая строка"

Стартовая строка запроса содержит информацию о методе запроса, относительном адресе и версии протокола в формате Метод URI HTTP/Версия. Стартовая строка ответа содержит версию протокола, код и статус ответа сервера в формате HTTP/Версия Код Статус.

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

        
          
          GET / HTTP/1.1
          GET / HTTP/1.1

        
        
          
        
      

Если страница существует и к ней есть доступ, то стартовая строка ответа будет такой:

        
          
          HTTP/1.1 200 OK
          HTTP/1.1 200 OK

        
        
          
        
      

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

  • OPTIONS — используется для определения возможностей сервера по преобразованию данных.
  • GET — используется для получения данных от сервера.
  • HEAD — то же, что и GET, но не содержит тело в сообщении ответа.
  • POST — используется для отправки данных на сервер.
  • PUT — используется для добавления новых или изменения существующих данных на сервере.
  • PATCH — то же, что и PUT, но используется для обновления части данных.
  • DELETE — используется для удаления данных на сервере.
  • TRACE — возвращает запрос от клиента таким образом, что в ответе содержится информация о преобразованиях запроса на промежуточных серверах.
  • CONNECT — переводит текущее соединение в TCP/IP-туннель. Обычно этот метод используется для установления защищённого SSL-соединения.

Код состояния в ответе сервера содержит информацию о результате обработки данных. Существует пять классов кодов состояний:

  • 1xx — обработка данных на сервере продолжается;
  • 2xx — успешная обработка данных;
  • 3xx — перенаправление запросов;
  • 4xx — ошибка по вине клиента;
  • 5xx — ошибка по вине сервера.

Самые популярные ответы сервера (коды состояния и статусы):

  • 200 OK в случае успешной обработки запроса.
  • 301 Moved Permanently если редирект используется на постоянной основе.
  • 307 Temporary Redirect если редирект используется временно.
  • 400 Bad Request если в запросе есть синтаксическая ошибка.
  • 403 Forbidden если запрос успешный, но сервер его не может выполнить, поскольку пользователь не имеет достаточных прав.
  • 404 Not Found если запрошенного ресурса не существует.
  • 500 Internal Server Error если работа программы на сервере выдала ошибку.

Все возможные статусы описаны в реестре кодов, а так же на справочных ресурсах.

Использование заголовков

Секция статьи "Использование заголовков"

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

  1. Основные заголовки, которые могут включаться в любые сообщения клиента и сервера.
  2. Заголовки запроса, которые используются только в сообщениях клиента.
  3. Заголовки ответа, которые используются только в сообщениях сервера.
  4. Заголовки сущности, которые описывают данные в сообщении.

Заголовки принято группировать в соответствии со списком выше и посылать их в соответствующем списку порядке. В стандартах для каждой версии HTTP описано довольно много заголовков, но можно использовать и свои.

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

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

Для того чтобы пользоваться сжатием, необходимо дать понять клиенту и серверу, что это вообще возможно и какой алгоритм сжатия применять. Выбор конкретного алгоритма обусловлен несколькими специфическими причинами. Например, программная поддержка на клиенте (чаще всего клиентом является браузер), реализация сжатия на сервере, особенности пересылаемых данных. В любом случае клиент должен сообщить серверу, что сжатие поддерживается, сервер должен сообщить клиенту, что данные сжаты и их необходимо распаковать перед использованием.

Например, для того чтобы сообщить серверу о поддержке сжатия в форматах gzip, br или deflate, нужно использовать заголовок:

        
          
          Accept-Encoding: gzip, br, deflate
          Accept-Encoding: gzip, br, deflate

        
        
          
        
      

Сервер для передачи данных в сжатом формате gzip должен послать заголовок:

        
          
          Content-Encoding: gzip
          Content-Encoding: gzip

        
        
          
        
      

Тело сообщения

Секция статьи "Тело сообщения"

Формат данных тела сообщения может быть нескольких типов, которые закреплены в спецификациях HTTP-протокола различных версий (HTTP/1.0 (стандарт RFC 1945), HTTP/1.1 (стандарт RFC 2616), HTTP/2 (черновик стандарта), HTTP/3 (черновик стандарта)). Чаще всего встречаются типы:

  • text/html.
  • application/json.
  • multipart/form-data.

На практике

Секция статьи "На практике"

Игорь Коровченко советует

Секция статьи "Игорь Коровченко советует"

Просмотр HTTP-сообщений из командной строки

Секция статьи "Просмотр HTTP-сообщений из командной строки"

В мире Unix-подобных операционных систем есть многофункциональная утилита curl, которая позволяет работать с протоколом HTTP. С одной стороны, с её помощью можно скачивать файлы, отправлять данные пользователей на сервер аналогично тому, как это делается через формы на сайтах, работать с API и даже отправлять письмо. С другой, это отличный способ познакомиться с работой протокола или протестировать веб-приложение, которое работает на стороне сервера.

Чтобы скачать главную страницу какого-то сайта (например, http://example.com), можно воспользоваться командой:

        
          
          curl http://example.com
          curl http://example.com

        
        
          
        
      

В терминале вы увидите HTML-код страницы — это тело сообщения ответа. Существует возможность посмотреть и полные сообщения запроса и ответа, добавив ключ -v:

        
          
          curl -v http://example.com*   Trying 93.184.216.34...* TCP_NODELAY set* Connected to example.com (93.184.216.34) port 80 (#0)> GET / HTTP/1.1> Host: example.com> User-Agent: curl/7.64.1> Accept: */*>< HTTP/1.1 200 OK< Age: 258083< Cache-Control: max-age=604800< Content-Type: text/html; charset=UTF-8< Date: Thu, 22 Jul 2021 15:42:57 GMT< Etag: "3147526947+ident"< Expires: Thu, 29 Jul 2021 15:42:57 GMT< Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT< Server: ECS (dcb/7F17)< Vary: Accept-Encoding< X-Cache: HIT< Content-Length: 1256<<!doctype html><html>* Connection #0 to host example.com left intact* Closing connection 0
          curl -v http://example.com
*   Trying 93.184.216.34...
* TCP_NODELAY set
* Connected to example.com (93.184.216.34) port 80 (#0)
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Age: 258083
< Cache-Control: max-age=604800
< Content-Type: text/html; charset=UTF-8
< Date: Thu, 22 Jul 2021 15:42:57 GMT
< Etag: "3147526947+ident"
< Expires: Thu, 29 Jul 2021 15:42:57 GMT
< Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
< Server: ECS (dcb/7F17)
< Vary: Accept-Encoding
< X-Cache: HIT
< Content-Length: 1256
<
<!doctype html>
<html>

* Connection #0 to host example.com left intact
* Closing connection 0

        
        
          
        
      

В выводе команды curl символы *, > и < являются маркерами типа информации, отображённой в выводе команды. * используется для сервисной информации о соединении, > — для обозначения запросов клиента (клиентом является curl), < — для обозначения ответов сервера.

В первой части вывода содержится информация о процессе установления соединения через протокол TCP:

        
          
          *   Trying 93.184.216.34...* TCP_NODELAY set* Connected to example.com (93.184.216.34) port 80 (#0)
          *   Trying 93.184.216.34...
* TCP_NODELAY set
* Connected to example.com (93.184.216.34) port 80 (#0)

        
        
          
        
      

Curl пытается соединиться с сетевым устройством с IP-адресом 93.184.216.34, поскольку именно этот адрес соответствует домену example.com. Строка после слова Connected... curl указывает, что соединение установлено. В последней части curl выводит информацию о прекращении соединения:

        
          
          * Connection #0 to host example.com left intact* Closing connection 0
          * Connection #0 to host example.com left intact
* Closing connection 0

        
        
          
        
      

Вторая часть вывода — полное HTML-сообщение запроса со стартовой строкой и заголовками (тело сообщения отсутствует):

  • > GET / HTTP/1.1 — Стартовая строка с методом запроса, адресом внутри сайта и версией протокола.
  • > Host: example.com — Заголовок с указанием хоста, на котором работает веб-сервер.
  • > User-Agent: curl/7.64.1 — Заголовок с информацией о клиенте, программе, запущенной у пользователя.
  • > Accept: */* — Заголовок с типами контента, которые клиент может корректно обработать.
  • > — После этой пустой строки могло быть тело запроса, но его редко используют в случае обработки данных методом GET.

Третья часть вывода — полное HTML-сообщение ответа веб-сервера со стартовой строкой, заголовками и телом, в котором передаётся HTML-код страницы:

< HTTP/1.1 200 OK — Стартовая строка с версией протокола, кодом и статусом ответа сервера.
< Age: 258083 — Заголовок с временем жизни контента в кэше (в секундах).
< Cache-Control: max-age=604800 — Заголовок для определения времени (в секундах) и типа кэширования на сервере.
< Content-Type: text/html; charset=UTF-8 — Заголовок с типом контента и кодировкой.
< Date: Thu, 22 Jul 2021 15:42:57 GMT — Заголовок с датой и временем отправки сообщения.
< Etag: "3147526947+ident" — Заголовок с версией контента.
< Expires: Thu, 29 Jul 2021 15:42:57 GMT — Заголовок с датой и временем, после которых контент считается устаревшим.
< Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT — Заголовок с датой и временем последнего изменения контента.
< Server: ECS (dcb/7F17) — Заголовок с именем веб-сервера. В нашем случае Elastic Cloud Server.
< Vary: Accept-Encoding — Заголовок, который отвечает за выбор стратегии кэширования и сжатия.
< X-Cache: HIT — Заголовок означает, что контент расположен на CDN (Content Delivery Network), а не на одном сервере.
< Content-Length: 1256 — Заголовок с информацией о длине контента в символах.
< — После этой пустой строки идёт тело ответа сервера, в нашем случае HTML-код страницы

Вы можете узнать больше о домене с помощью разных сервисов, например, с помощью domain.glass.