Обзор протокола HTTP
HTTP — это протокол для получения ресурсов, например, HTML-документов. Он лежит в основе обмена данными в Интернете и является протоколом клиент-серверного взаимодействия, что означает инициирование запросов к серверу самим получателем, обычно веб-браузером. Готовый документ как правило состоит из различных ресурсов, таких как текстовое содержимое, описание структуры, изображения, видео-файлы, скрипты и т.д.
Клиент и сервер взаимодействуют, обмениваясь отдельными сообщениями (а не потоком данных). Сообщения, отправляемые клиентом, называются запросами (англ. request), а сообщения от сервера называются ответами (англ. response).
Разработанный в начале 1990-х годов, HTTP является расширяемым протоколом, который развивался с течением времени. Это протокол прикладного уровня, который использует соединение TCP (или TLS-защищённый TCP) для пересылки сообщений, однако теоретически может быть использован любой другой надёжный транспортный протокол. Благодаря своей расширяемости, HTTP используется не только для получения гипертекстовых документов, но и для изображений и видео, а также для отправки содержимого серверам, например, с помощью HTML-форм. HTTP также может быть использован для получения частей документа с целью обновления веб-страницы по запросу.
Составляющие систем, основанных на HTTP
HTTP — это клиент-серверный протокол, то есть запросы отправляются какой-то одной стороной — пользовательским агентом (либо прокси от его имени). Чаще всего в качестве пользовательского агента выступает веб-браузер, но необязательно, например, им может быть робот, индексирующий веб-страницы для поисковых систем.
Каждый отдельный запрос отправляется серверу, который обрабатывает его и возвращает ответ. Между клиентом и сервером как правило существуют многочисленные посредники, называемые прокси, которые выполняют различные операции и работают как шлюзы или, например, кэш.
Обычно между браузером и сервером гораздо больше различных устройств-посредников, которые играют какую-либо роль в обработке запроса: маршрутизаторы, модемы и т.д. Благодаря тому, что Интернет имеет многоуровневую структуру, эти посредники "спрятаны" на сетевом и транспортном уровнях. В этой системе уровней HTTP занимает самый верхний уровень, который называется "прикладным" или "уровнем приложений". Хотя знания об уровнях имеют важное значение для понимания работы сети и диагностики возможных проблем, но не обязательны для описания HTTP.
Клиент: пользовательский агент
Пользовательский агент (англ. user agent) — это любой инструмент или устройство, действующие от лица пользователя. Эту задачу преимущественно выполняет веб-браузер, но это также могут программы, которые используются инженерами и веб-разработчиками для отладки своих приложений.
Браузер всегда является той сущностью, которая инициирует запрос. Сервер обычно этого не делает, хотя за годы существования сети были придуманы способы, которые могут позволить выполнить запросы со стороны сервера.
Чтобы отобразить веб-страницу, браузер отправляет начальный запрос для получения HTML-документа. После этого браузер изучает этот документ и запрашивает дополнительные файлы, необходимые для отображения веб-страницы (исполняемые скрипты, CSS-стили, изображения и видео-файлы). Далее браузер соединяет все эти ресурсы для отображения их пользователю в виде единого документа — веб-страницы. Скрипты, выполняемые самим браузером, могут получать дополнительные ресурсы на последующих этапах обработки веб-страницы, и браузер соответствующим образом обновляет отображение этой страницы.
Веб-страница является гипертекстовым документом. Это означает, что некоторые части отображаемого текста являются ссылками, которые могут быть активированы (обычно нажатием кнопки мыши) для получения новой веб-страницы. Это позволяет пользователю "перемещаться" по страницам сети Интернет. Браузер преобразует эти переходы в HTTP-запросы и в дальнейшем отображает полученные HTTP-ответы в понятном для пользователя виде.
Веб-сервер
На другой стороне коммуникационного канала расположен сервер, который обслуживает (англ. serve) запросы клиента. Сервер представляется некой одной виртуальной машиной, но фактически это может быть группа серверов, между которыми балансируется нагрузка, то есть перераспределяются запросы различных пользователей, либо другим программным обеспечением (таким как кеширующие серверы, серверы баз данных, серверы приложений электронной коммерции и другие).
Сервер не обязательно расположен на одном компьютере, и наоборот — несколько серверов могут быть расположены на одной и той же машине.
Начиная с версии HTTP/1.1 заголовок Host
позволяет нескольким серверам даже использовать один тот же IP-адрес.
Прокси
Между веб-браузером и сервером находятся большое количество сетевых узлов, передающих HTTP-сообщения. Из-за многоуровневой структуры большинство из них оперируют на транспортном, сетевом или физическом уровнях, становясь прозрачным для HTTP и потенциально снижая производительность. Эти промежуточные узлы на уровне приложений называются прокси. Они могут быть прозрачными, то есть пересылать запросы без преобразований, и непрозрачными — изменяющими запрос каким-либо образом перед передачей его другому серверу. Прокси могут выполнять различные функций:
- кеширование (кеш может быть публичным или приватными, как кеш браузера)
- фильтрация (как сканирование антивирусом или родительский контроль)
- балансирование нагрузки (чтобы позволить нескольким серверам обслуживать запросы)
- аутентификация (для контроля доступа к разным ресурсам)
- протоколирование (позволяет хранить историю операций)
Основные аспекты HTTP
HTTP является простым
HTTP был спроектирован так, чтобы быть простым и понятным для человека, даже с учётом сложности, добавленной в HTTP/2 в виде инкапсуляции HTTP-сообщений в кадры. HTTP-сообщения могут быть прочитаны и поняты людьми, что упрощает тестирование для разработчиков и упрощает работу новичкам.
HTTP является расширяемым
Введённые в HTTP/1.0 HTTP-заголовки сделали этот протокол лёгким для расширения и экспериментирования. Новая функциональность может быть добавлена простым соглашением между клиентом и сервером о семантике нового заголовка.
HTTP не имеет состояния, но имеет сессию
HTTP не имеет состояния: не существует связи между двумя запросами, которые последовательно выполняются по одному соединению. Это добавляет некоторые проблемы для пользователей, которые хотят взаимодействовать с определённой страницей последовательно, например, при использовании корзины в электронном магазине. Но хотя ядро HTTP не имеет состояния, HTTP-куки позволяют использовать сессии с сохранением состояния. Используя расширяемость заголовков, HTTP-куки позволяют при каждом HTTP-запросе использовать сессии для сохранения контекста или состояния.
HTTP и соединения
Соединение управляется на транспортном уровне, и поэтому принципиально выходит за границы HTTP. HTTP не требует, чтобы транспортный протокол был основан на соединениях, необходима только надёжность, то есть отсутствие потерянных сообщений (или как минимум информирование о таких потерях). Среди двух наиболее распространённых транспортных протоколов Интернета, TCP является надёжным, а UDP — нет. Поэтому HTTP полагается на стандарт TCP, который основан на соединениях.
Прежде чем клиент и сервер смогут обменяться HTTP-запросом и ответом, они должны установить TCP-соединение, этот процесс требует нескольких циклов обмена данными. Поведение HTTP/1.0 по умолчанию заключается в открытии отдельного TCP-соединения для каждой пары запрос-ответ. Это менее эффективно, чем совместное использование одного TCP-соединения, когда несколько запросов отправляются последовательно.
Для смягчения этого недостатка, в HTTP/1.1 была добавлена конвейерная обработка (которую оказалось трудно реализовать) и постоянные соединения: лежащее в основе TCP соединение можно частично контролировать с помощью заголовка Connection
.
HTTP/2 сделал следующий шаг, добавив мультиплексирование сообщений по одному соединению, помогающее держать соединение «тёплым» и более эффективным.
Проводятся эксперименты по разработке лучшего транспортного протокола, более подходящего для HTTP. Например, Google экспериментирует с QUIC, который основан на UDP, для предоставления более надёжного и эффективного транспортного протокола.
Чем можно управлять в HTTP
Расширяемая природа HTTP со временем позволила обеспечить больший контроль и функциональность Интернета. Методы кеширования и аутентификации были функциями, обрабатываемыми на ранних этапах развития HTTP. Возможность ослабить ограничение источника, напротив, была добавлена только в 2010-х годах.
Ниже перечислены наиболее распространённые возможности HTTP:
- Кеширование HTTP может управлять кешированием документов. Сервер может инструктировать прокси и клиентов, указывая что и как долго кешировать. Клиент может инструктировать прокси промежуточных кешей игнорировать хранимые документы.
- Ослабление ограничений источника Для предотвращения шпионских и других нарушающих конфиденциальность вторжений, веб-браузеры обеспечивают строгое разделение между веб-сайтами. Только страницы из того же источника могут получить доступ к информации на веб-странице. Хотя такие ограничения усложняют работу сервера, заголовки HTTP могут ослабить строгое разделение на стороне сервера, позволяя документу комбинировать информацию из различных доменов. Это может быть необходимо в том числе по причинам, связанным с безопасностью.
- Аутентификация
Некоторые страницы могу быть защищены и доступны только специальным пользователям.
Базовая аутентификация может предоставляться через HTTP, с помощью заголовка
WWW-Authenticate
и подобных ему, либо с помощью настройки сессии и использования HTTP-кук. - Прокси и туннелирование Серверы и клиенты часто расположены в подсетях и скрывают свои истинные IP-адреса от других компьютеров. HTTP-запросы идут через прокси для преодоления этого сетевого барьера. Не все прокси являются HTTP-прокси. Например, SOCKS-протокол оперирует на более низком уровне. Другие, такие как FTP, могут быть обработаны этими прокси.
- Сессии Использование HTTP-кук позволяет связать запрос с состоянием сервера. Это создаёт сессию, хотя сам HTTP — протокол без состояния. Это полезно не только для реализации корзины в интернет-магазине, но также для любых сайтов, позволяющих пользователю настраивать их поведение.
HTTP-поток
Когда клиент хочет взаимодействовать с сервером, являющимся конечным сервером или промежуточным прокси, он выполняет следующие шаги:
-
Открытие TCP соединения: TCP-соединение будет использоваться для отправки запроса (или запросов) и получения ответа. Клиент может открыть новое соединение, переиспользовать существующее или открыть несколько TCP-соединений к серверу.
-
Отправка HTTP-сообщения: HTTP-сообщения (до HTTP/2) являются человекочитаемыми. Начиная с HTTP/2, отдельные сообщения инкапсулируются в кадры, делая невозможным их чтение напрямую, но принципиально остаются такими же. Например:
httpGET / HTTP/1.1 Host: developer.mozilla.org Accept-Language: fr
-
Чтение ответа от сервера, например:
httpHTTP/1.1 200 OK Date: Sat, 09 Oct 2010 14:28:02 GMT Server: Apache Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT ETag: "51142bc1-7449-479b075b2891b" Accept-Ranges: bytes Content-Length: 29769 Content-Type: text/html <!doctype html>… (here come the 29769 bytes of the requested web page)
-
Закрытие или переиспользование соединения для следующих запросов.
Если активирована конвейерная обработка HTTP, можно отправить несколько запросов, не дожидаясь полного получения первого ответа. Конвейерную обработку HTTP оказалось сложно реализовать в существующих сетях, где старые части программного обеспечения сосуществуют с современными версиями. Конвейерная обработка HTTP была заменена в HTTP/2 более надёжным мультиплексированием запросов внутри кадра.
HTTP-сообщения
Сообщения в HTTP/1.1 и более ранних версиях человекочитаемы. В версии HTTP/2 сообщения встроены в новую бинарную структуру — кадр (англ. frame), которая поддерживает оптимизации, такие как сжатие заголовков и мультиплексирование. Даже если только часть исходного HTTP-сообщения отправляется в этой версии HTTP, семантика каждого сообщения остаётся неизменной, и клиент воссоздаёт (виртуально) исходный HTTP/1.1-запрос. Поэтому полезно понимать HTTP/2-сообщения в формате HTTP/1.1.
Существует два типа HTTP-сообщений: запросы и ответы, для каждого из них есть свой формат.
Запросы
Пример HTTP-запроса:
Запросы содержат следующие элементы:
- HTTP-метод, обычно это глагол (
GET
,POST
) или существительное (OPTIONS
,HEAD
), определяющее операцию, которую клиент хочет выполнить. Самые распространённые операции — это получение ресурса (используяGET
) или отправка HTML-формы (используяPOST
), хотя существуют и другие. - Путь к ресурсу. URL ресурса не содержит элементов, которые очевидны из контекста, например протокол (
http://
), домен (developer.mozilla.org
) или TCP-порт (80
). - Версия HTTP-протокола.
- Необязательные заголовки, предоставляющие дополнительную информацию для сервера.
- Тело — для некоторых методов (таких как
POST
) содержит отправленный ресурс.
Ответы
Пример ответа:
Ответы содержат следующие элементы:
- Версия HTTP-протокола.
- Код состояния, сообщающий об успешности запроса или причине неудачи.
- Сообщение состояния — краткое описание кода состояния.
- HTTP-заголовки, подобно заголовкам в запросах.
- Необязательно: тело, содержащее получаемый ресурс.
API, основанные на HTTP
Наиболее распространённым API, которое основано на HTTP является Fetch API, который может быть использован для отправки HTTP-запросов из JavaScript. Fetch API заменяет XMLHttpRequest
API.
Другой API — события, отправляемые сервером, использует HTTP как транспортный механизм.
Используя интерфейс EventSource
, клиент открывает соединение и устанавливает обработчики событий.
Браузер автоматически преобразует сообщения, которые поступают по HTTP, в соответствующие объекты Event
.
Затем он доставляет их до обработчиков событий, которые были установлены для событий указанного типа
или в обработчик onmessage
, если специализированные обработчики не были установлены.
Заключение
HTTP — расширяемый и лёгкий в использовании протокол. Клиент-серверная структура в сочетании с возможностью добавления заголовков позволяет HTTP развиваться вместе с расширяющимися возможностями Интернета.
Несмотря на то, что HTTP/2 добавляет некоторую сложность, помещая HTTP-сообщения в кадры для улучшения производительности, базовая структура сообщений осталась такой же как и в HTTP/1.0. Работа с сессиями остаётся простой, её можно исследовать и отлаживать с помощью Сетевого монитора.