HTTP – текстовый протокол, с помощью которого взаимодействуют клиент, например, браузер и сервер. Работает это так. Пользователь шлет определенный запрос на сервер, запрашивая или передавая нужные данные, а сервер, в зависимости от запроса, выполняет нужную логику и возвращает результат, обычно это HTML-страница либо редирект.
Для того чтобы посмотреть, как работает HTTP, мы будем использовать сервис HTTP Server, созданный специально для экспериментов. Он включает в себя ненастоящие данные, с которыми можно попрактиковаться. Для запросов используется специальная утилита, которая называется telnet (пример HTTP-запроса, выполненного с помощью утилиты telnet).
# Передаем адрес сайта и указываем tcp порт
# После этого происходит подключение к серверу по протоколу tcp
telnet http.hexlet.app 80
HTTP – протокол прикладного уровня. Другими словами, он предназначен для общения между двумя программами (клиентом и сервером), находящимися на разных компьютерах. Но, сам по себе, HTTP не может соединять два удаленных компьютера. Для этого используются другие протоколы, среди которых TCP. Именно TCP позволяет соединить программы на удаленных компьютерах, создав канал для общения друг с другом. Для этого нужно знать два параметра: ip-адрес компьютера, к которому нужно подключиться, и порт, на котором "висит" нужная программа.
Команда telnet выше делает именно это, она выполняет соединение по TCP и только после этого входит в режим взаимодействия по HTTP. При условии, что указан правильный ip-адрес и порт для соединения. И на этом моменте возникает два вопроса:
Мы передали адрес сайта, откуда берется ip-адрес? Любой адрес сайта это просто имя, за которым скрывается ip-адрес. Имя задано для удобства, так его проще запомнить. Однако все сетевые программы, среди которых браузеры и telnet, выполняют преобразование имени сайта в его ip-адрес. Делается это с помощью системы DNS, еще одного столпа интернета.
# Пример того, как можно узнать ip-адрес с помощью утилиты ping
# В вашем случае адрес может быть другим, ip-адреса могут меняться
# Опция -с устанавливает количество отправляемых пакетов
ping -c 4 http.hexlet.app # 188.114.97.0
# Затем можно использовать его для соединения с сервером
telnet 188.114.97.0 80
Почему порт имеет номер 80? Это общепринятое соглашение. Сайты, доступные по HTTP, доступны на порту 80, а по HTTPS – на порту 443. Именно поэтому в браузерах порты не указываются, браузер подставляет их автоматически.
Если соединение произошло успешно, то telnet выводит на экран такие строчки:
telnet http.hexlet.app 80
Trying 188.114.97.0...
Connected to http.hexlet.app.
Escape character is '^]'.
После подключения веб-сервер входит в режим ожидания HTTP-запроса. Осталось его послать.
Что из себя представляет сам запрос?
Запрос состоит из нескольких частей. Первая часть — стартовая строка (request line). Вторая — заголовки.
В стартовой строке мы указываем специальное слово, еще говорят "глагол". В HTTP описаны разные глаголы, но мы сейчас не будем вдаваться в подробности. Просто скажем, что они определяют, как реагировать на этот запрос. И в данном случае мы будем использовать глагол HEAD. Он очень простой, и просит сервер отдать только заголовки, без содержимого. Более распространенным является GET. Именно с помощью GET мы запрашиваем содержимое сайта.
После глагола указывается путь к ресурсу request URI. Если мы указываем /
, это обозначает просто корень сайта. Ресурс может быть любым, например, /users
— может быть ресурсом пользователей, а /courses
— ресурсом курсов. Имя ресурса зависит не только от того, к какому ресурсу мы хотим получить доступ, но и от сервера. Разные серверы предоставляют доступ к разным ресурсам.
Дальше все, что нужно сделать, это указать название протокола и его версию. В этом курсе рассматриваются версии HTTP 1.0 и 1.1, это основа протокола и знакомство с ним стоит начинать именно с них. Между версиями есть принципиальные отличия, которые нужно хорошо знать и понимать. Версия 1.0 продолжает использоваться в различных целях утилитами командной строки.
В принципе этого достаточно, и для 1.0 больше ничего делать не нужно:
HEAD /http-protocol/example HTTP/1.0
Дальше идут заголовки. Что это? Заголовки позволяют передавать дополнительную информацию, например браузеры предоставляют информацию о себе, чтобы было понятно откуда идет запрос. Кроме этого они указывают какие форматы сжатия поддерживают, в каком формате готовы принимать ответ и так далее. Количество стандартных заголовков достаточно большое, помимо них можно добавлять любые свои.
Давайте рассмотрим, как выглядят заголовки. Мы указываем имя и через двоеточие какое-то значение: REFERER: value. Заголовки часто указывают заглавными буквами, но регистр здесь не важен. Порядок заголовков также не специфицирован. В каком бы порядке мы ни передали заголовки, тело ответа будет разбираться только все вместе.
Браузерами используется много заголовков, например, user-agent. Этот заголовок используется для аналитики, а также, когда необходимо адаптировать страницы сайта под разные экраны или браузеры. Но и без него все должно работать:
HEAD /http-protocol/example HTTP/1.0
User-Agent: google сhrome
Важно помнить, поскольку это протокол, и у него есть определенные правила, то нарушать их нельзя. HTTP — текстовый протокол. Все правила основаны на простых соглашениях. Например, несколько заголовков отделяются друг от друга переводом строки (и никак иначе!). Мы не можем записать их в одну строку, через запятую или как-то еще. Все очень строго. А каким образом сервер поймет, что вы закончили передавать данные? Это должен быть какой-то маркер, определитель. В HTTP это делается с помощью двух переводов строки. После этого сервер считает что все данные были отправлены и больше данных не будет. То есть фактически два перевода строки (перевод после последнего заголовка и пустая строка) приводят к отправке данных.
Что из себя представляет ответ?
Давайте сделаем запрос и посмотрим, что нам вернется в ответ. Сделаем HEAD запрос и посмотрим, что будет возвращено:
telnet http.hexlet.app 80
Trying 188.114.97.0...
Connected to http.hexlet.app.
Escape character is '^]'.
HEAD /http-protocol/example HTTP/1.0
host: http.hexlet.app
HTTP/1.1 200 OK
Date: Sat, 18 Jan 2020 09:24:50 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2020-01-18-09; expires=Mon, 17-Feb-2020 09:24:50 GMT; path=/; domain=.google.com; Secure
Set-Cookie: NID=196=wsHLMAMfnAaSyF7zduokI8TJeE5UoIKPHYC58HYH93VMnev9Nc2bAjhRdzoc4UhmuOd7ZVCorDnzGDe51yPefsRMeVyOFnYdHYYgQNqI8A1dYuk4pDK4OJurQgL4lX8kiNGSNi_kkUESFQ-MqLCB_YspxA9JRejhZdkTRtGyHNk; expires=Sun, 19-Jul-2020 09:24:50 GMT; path=/; domain=.google.com; HttpOnly
Accept-Ranges: none
Vary: Accept-Encoding
Connection closed by foreign host.
В ответ к нам приходит response. Он состоит из status line HTTP/1.1 200 OK
. Это строка ответа, в которой указан протокол (здесь он не совпадает, потому что сервер работает по HTTP/1.1
, про который мы узнаем в следующем уроке) и статус ответа 200 OK
. В HTTP определено множество различных статусов (400, 500 и т.д.). Они могут информировать, что информация была не найдена, были ошибки на сервере и т.д. Все статусы имеют мнемоническое название, которое передается так же последним значением. 200 и OK
обозначает, что все прошло хорошо — success!
Далее выводится большое количество различных заголовков. В них нет ничего сложного, и их не нужно все учить (есть какие-то общие, и они достаточно понятны). Все заголовки состоят из ключа, двоеточия и значения. Можно заметить, что есть вещи, связанные с кодировкой, кешированием. Некоторые заголовки специфичны для текущего сервера. Например, X-XSS-Protection: 0
, где X
указывает на кастомный заголовок. Но никакой веб-сервер, никакой веб-браузер не будут ломаться при посылке таких дополнительных заголовков.
Именно в HTTP 1.0 в конце после получения данных происходит закрытие соединения.
В конце мы видим одну интересную деталь: Connection closed by foreign host. Запрос соединения был закрыт внешним хостом. Так работает практически все в интернете. Обычно серверы настроены на 30-секундный интервал и закрывают соединение, если в течение этого интервала ничего не приходит.
Поэтому с telnet новичкам работать чуть тяжелее. Они медленно набирают запрос, и за это время соединение закрывается, что довольно неприятно. Поэтому лучше делать записи в отдельном файле и после этого вставлять их в telnet.
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.