Что делает web сервер получив запрос от вашего интернет браузера
В статье про устройство веба и как происходит серфинг я упомянул, что браузер отправляет запрос к веб-серверу. Но что представляет из себя запрос? Это куча машиночитаемых квантовых кодов и сингулярных шифров? Программистская магия? Вовсе нет.
- При встрече на протянутую руку принято отвечать рукопожатием. Отсутствие рукопожатия — это тоже ответ, иногда даже более красноречивый, чем само рукопожатие.
- Девушкам же руку не протягивают — это тоже часть протокола. Можно и им руку протянуть, но в большинстве случаев не поймут, а в некоторых странах заставят жениться.
- Электрические розетки — хотя в разных странах они разные, внутри одной страны они одинаковы.
- Разъёмы для кабелей — USB type B, USB type C, mini USB, micro USB. Производители приняли внегласный протокол и производят кабели и устройства именно таких форматов, иначе при прочих равных пользователи их не поймут и не будут покупать их продукцию (исключение — Apple).
- Правила дорожного движения — знаки, разметка и светофоры помогают пешеходам дойти, а автомобилистам доехать до места назначения без происшествий.
- Формы налоговых деклараций и прочих бюрократических документов.
Любой из протоколов нас ни к чему не обязывает, это не ГОСТ, он лишь рекомендует поступать так или иначе, если мы хотим добиться желаемой цели — понимания от окружающих людей, одобрения от покупателей, сохранения продаж, избежания аварий и штрафов, получения веб-страницы от сервера.
Чтобы понять, как браузер общается с сервером, нужно думать как браузер, нужно стать браузером.
Порты — это как номера квартир в доме. Чтобы доставить письмо, почтальону нужно знать не только дом, но и номер квартиры. Причём в некоторых квартирах почтальону ответят, если он в них постучится, а другие — нет, потому что там никто не живёт. А кто-то ответит, что адресат уже давно здесь не живёт и дадут новый адрес почтальону (редирект запроса).
В компьютерных сетях всё точно также. На одном адресе (IP или доменном имени) могут висеть и ожидать запросов несколько портов одновременно. Чтобы избежать путаницы, сообщество разработчиков договорилось для наиболее популярных серверов выделять одни и те же порты: SSH — 22, FTP — 21, база данных MySQL — 3306, веб-сервера — 80. Это лишь соглашение и рекомендация, можно поднять какой угодно сервер на каком угодно порту, но для клиентов это скорее всего станет неожиданностью.
Введём в терминале такие строки запроса.
После этого браузер разбирает ответ, убирает техническую информацию и отображает html-страницу в кодировке UTF-8 — так ему сказал сервер в заголовке Content-Type. Если в HTML включены CSS, Javascript, картинки, то браузер запросит их отдельными запросами ровно таким же образом. Если он их уже запрашивал раньше, то возьмёт из локального кэша. Поэтому первый раз страницы грузятся визуально дольше.
Разберём структуру запроса и ответа более детально.
Каждый запрос имеет один и тот же формат:
протокол
Относительный путь (без доменного имени) до документа. В нашем примере указан корень /, но путь может быть любым: /index.php, /catalog/food/milk. Под документом понимаются не только файлы с расширением .html, но и любые другие файлы, например картинки, .css, .js.
метод
Определяет, что веб-сервер должен сделать с документом, найденным по указанному «/пути».
На практике примерно 80% запросов приходится на GET, 15% — на POST и 5% — на все остальные методы.
Заголовки
Они опциональны (в нашем примере их не было вовсе) и подсказывают веб-серверу, как именно нужно обработать запрос. Например, что клиент отправляет запрос в виде текста с кодировкой utf-8, а ожидает получить json в кодировке cp1251.
Наиболее частые на практике заголовки:
- Accept — в каком формате ожидаем ответ: обычный текст, html, xml, json, что угодно ещё.
- Accept-Charset — кодировка тела запроса: utf8, cp1251, koi8.
- Authorization — данные для авторизации между запросами. Здесь чаще всего передаются токены API. Авторизация между запросами будет рассмотрена ниже.
- Accept-Language — список языков, которые нас бы устроили. Например: «Accept-Language: ru».
- Cache-Control — настройки кэширования страниц
- Cookie — известные браузеру куки. В них сохраняются идентификаторы сессий и пользовательские предпочтения.
- Referrer — с какой страницы был сделан текущий запрос. Полезно для аналитики сайта и для возвращения юзера на первоначальную страницу после регистрации, например.
- User-Agent — тип клиента (чаще всего тип вашего браузера). Пример: «Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36». Это поле часто используется на сервере, чтобы отслеживать количество запросов с одного устройства и блокировать их при превышении лимита. Однако это не панацея, ведь после блокировки злоумышленник может поменять User-Agent на любой другой.
Обратите внимание, что POST запрос очень похож на GET, мы даже обращаемся к тому же документу «/». Однако есть и отличия:
- вместо второй пустой строки в конце запроса содержатся данные: «name=Max»
- эти данные могут быть в разном формате, поэтому мы должны явно указать веб-серверу, что это данные из формы — application/x-www-form-urlencoded
- также мы сообщаем серверу, что в теле запроса содержится ровно 8 символов — «Content-Length: 8». Это техническое поле, которое браузер выполняет на лету, а нам приходится считать самим.
Можно заметить, что структура ответа похожа на структуру запроса. Но есть несколько нюансов. Первая строка ответа выглядит иначе:
протокол
Значение поля то же самое, что и в запросе. Но может отличаться от версии, что запросил браузер, если веб-сервер её не понимает.
статус и пояснение
Статусов больше сотни, но не все их них используются браузерами. Некоторые предусмотрены на далёкое будущее, а некоторые слишком специфичны.
Первая цифра статуса указывает на класс:
заголовки
Заголовки сервера выполняют ту же роль, что и заголовки запроса. Есть общие заголовки, как Cache-Control, но есть и свои уникальные.
Тело ответа также отделяется от группы заголовков пустой строкой. При этом в теле может передаваться что угодно — текст, html, json, xml, картинки и прочие файлы. Все они отдаются браузеру в одинаковом формате, но с отличающемся заголовком Content-Type, который и поясняет браузеру, как отобразить контент пользователю: как html-страницу, как картинку, показать встроенный в браузер PDF-просмотрщик или начать скачивание файла.
Про аутентификацию и авторизацию
В жизни это ограничение обходят двумя путями:
Вторая версия протокола отличается от первой чуть меньше, чем полностью.
Эта статья — короткий и простой перевод статьи «What happens when. », опубликованной на Гитхабе. В ней автор подробно рассказывает, что именно происходит внутри компьютера, когда мы вводим в браузере адрес сайта и нажимаем энтер. Мы убрали излишние технические подробности вроде IRQ-прерываний и ARP-запросов и добавили картинки, чтобы было проще понять суть.
Начало
Мы ввели адрес сайта — thecode.media — и нажали энтер. Что происходит дальше?
Поиск сервера в интернете
Каждый сайт в сети физически хранится на каком-то сервере. Как только браузер от нас получил адрес сайта, он должен понять, к какому серверу обратиться за данными. Но то, что мы называем адресом, на самом деле не адрес, а доменное имя.
👉 Проще говоря, когда вы садитесь в такси и говорите «Мне в „Мегу“», вы назвали водителю не адрес, а доменное имя. Водитель уже сам должен знать, где в вашем городе «Мега».
Так вот: теперь задача браузера — определить по доменному имени адрес, на который отправлять запрос. В мире интернета этот адрес называется IP-адресом. Он есть у каждого сервера и выглядит, например, так:
- Сначала смотрит, посещали мы этот сайт раньше или нет. Если посещали — возьмёт IP-адрес из истории. Так же, как водитель, который тысячу раз ездил в «Мегу».
- Если не посещали — посмотрит в конфигурационных файлах операционной системы. Иногда для ускорения работы некоторые IP-адреса можно прописать в конфигурации компьютера, чтобы он сразу знал, куда обращаться.
- Если в настройках такого нет, браузер смотрит недавние адреса в роутере, через который компьютер подключается к интернету.
- Если и там нет, то браузер отправляет запрос на DNS-сервер. Там точно всё есть, но результат получится медленнее, чем в остальных способах.
DNS-сервер — это такая служба в интернете, которая отвечает всем желающим на вопрос «Какой IP у такого-то домена?». Таких серверов в интернете много, и каждый из них знает про свою часть сети. Если у ближайшего сервера нет записей о нашем домене, то он отвечает «Я не знаю, спроси у DNS-сервера покрупнее, вот его адрес». В итоге браузер найдёт DNS-сервер, который знает то, что нам нужно, и получит IP-адрес сервера с сайтом.
Что ещё прочитать на эту тему:
Отправка запроса
Браузер нашёл IP-адрес сервера, на котором располагается наш сайт, и отправляет по этому адресу запрос типа «Я знаю, что у тебя есть вот такой домен. Мне нужна вот такая страница с этого домена с такими-то параметрами. Дай, пожалуйста».
Сервер думает
Когда сервер получает запрос от браузера и с адресом всё в порядке, он начинает готовить данные к отправке. Для этого он смотрит, какие серверные программы отвечают за этот домен, и говорит им «Соберите мне вот эту страницу, чтобы я её отправил в браузер». Например, на сервере может стоять Вордпресс или PHP-обработчик, который на лету собирает страницу из разных фрагментов кода.
Отправка данных в браузер
Как только сервер получил от своих внутренних программ всё, что ему нужно, он отправляет результат в браузер.
Для этого он нарезает все данные на мелкие пакеты данных по 8 килобайт, нумерует их и отправляет браузеру. Так делается для того, чтобы одновременно передавать много пакетов — в этом случае загрузка идёт быстрее. Нумерация нужна для того, чтобы браузер потом собрал все пакеты в одно целое и получил исходный документ. Если по пути пакет потерялся, браузер говорит серверу «У меня потерялись такие-то пакеты, отправь их ещё раз». И так до тех пор, пока браузер не соберёт все пакеты.
Браузер думает
Когда все пакеты собраны, браузер разбирает документ на составляющие:
- HTML;
- CSS;
- JavaScript;
- прочий код, который браузер может выполнить.
Это нужно для того, чтобы браузер построил DOM-модель страницы. Такая модель содержит:
- все элементы, которые есть на странице;
- связи между ними;
- как они взаимодействуют между собой;
- что умеют и как реагируют на действия пользователя.
На основе DOM-модели браузер в итоге будет рисовать страницу на экране.
Отрисовка страницы
Последнее, что нужно сделать браузеру, — взять DOM-модель, найти в ней все видимые элементы и нарисовать их на экране. Если есть JavaScript-код, то он выполняется либо до отрисовки, либо после, смотря как работает скрипт.
Иногда во время отрисовки страницы браузер может снова запросить данные у сервера. В этом случае браузер рисует то, что есть, а остальное — когда придут данные. Пока данных нет, на странице могут быть пустые места — например, браузер отрисовал верхнее меню и статью, но ещё не подгрузил видео с ютуба.
Всё готово
Когда страница загрузилась и браузер всё нарисовал, мы видим готовый результат. Но даже сейчас браузер может продолжать работать над страницей:
Простыми словами объясняем, как браузер подключается и общается с сервером.
Поэтому первым делом браузеру нужно понять, какой IP-адрес у сервера, на котором находится сайт.
Такая информация хранится в распределенной системе серверов — DNS (Domain Name System). Система работает как общая «контактная книга», хранящаяся на распределенных серверах и устройствах в интернете.
Однако перед тем, как обращаться к DNS, браузер пытается найти запись об IP-адресе сайта в ближайших местах, чтобы сэкономить время:
- Сначала в своей истории подключений . Если пользователь уже посещал сайт, то в браузере могла сохраниться информация c IP-адресом сервера.
- В операционной системе . Не обнаружив информации у себя, браузер обращается к операционной системе, которая также могла сохранить у себя DNS-запись. Например, если подключение с сайтом устанавливалось через одно из установленных на компьютере приложений.
- В кэше роутера , который сохраняет информацию о последних соединениях, совершенных из локальной сети.
Не обнаружив подходящих записей в кэше, браузер формирует запрос к DNS-серверам, расположенным в интернете.
Как только браузер узнал IP-адрес нужного сервера, он пытается установить с ним соединение. В большинстве случаев для этого используется специальный протокол — TCP.
TCP — это набор правил, который описывает способы соединения между устройствами, форматы отправки запросов, действия в случае потери данных и так далее.
Например, для установки соединения между браузером и сервером в стандарте TCP используется система «трёх рукопожатий». Работает она так:
- Устройство пользователя отправляет специальный запрос на установку соединения с сервером — называется SYN -пакет.
- Сервер в ответ отправляет запрос с подтверждением получения SYN-пакета — называется SYN/ACK -пакет.
- В конце устройство пользователя при получении SYN/ACK-пакета отправляет пакет с подтверждением — ACK -пакет. В этот момент соединение считается установленным.
Задача браузера — как можно подробнее объяснить серверу, какая именно информация ему нужна .
Сервер получил запрос от браузера с подробным описанием того, что ему требуется. Теперь ему нужно обработать этот запрос. Этой задачей занимается специальное серверное программное обеспечение — например, nginx или Apache. Чаще всего такие программы принято называть веб-серверами.
Когда ответ сформирован, он отправляется веб-сервером обратно браузеру. В ответе как правило содержится контент для отображения веб-страницы, информация о типе сжатия данных, способах кэширования, файлы cookie, которые нужно записать и так далее.
👉 Чтобы обмен данными был быстрым, браузер и сервер обмениваются сразу множеством небольших пакетов данных — как правило, в пределах 8 КБ. Все пакеты имеют специальные номера, которые помогают отслеживать последовательность отправки и получения данных.
Браузер распаковывает полученный ответ и постепенно начинает отображать полученный контент на экране пользователя — этот процесс называется рендерингом .
Сначала браузер загружает только основную структуру HTML-страницы. Затем последовательно проверяет все теги и отправляет дополнительные GET-запросы для получения с сервера различных элементов — картинки, файлы, скрипты, таблицы стилей и так далее. Поэтому по мере загрузки страницы браузер и сервер продолжают обмениваться между собой информацией.
Параллельно с этим на компьютер как правило сохраняются статичные файлы пользователя — чтобы при следующем посещении не загружать их заново и быстрее отобразить пользователю содержимое страницы.
Как только рендеринг завершен — пользователю отобразится полностью загруженная страница сайта.
Об этом спрашивают на собеседованиях. Структурированное понимание этого может помочь вам, даже если вы давно строите сложные архитектурные процессы или кодите 20-ый год подряд. Я — программист уже много лет, последние пару из которых пишу на Go в Каруне. Работа работой, а внутренний исследователь не дремлет. И вот я наконец-то решил привести в порядок информацию, разбросанную по разным закоулкам чертогов разума, по добротным книгам и статьям на тему сетевых технологий.
Хочу представить краткую выжимку о работе протоколов. А если тема окажется интересной, могу продолжить работать с ней более детально. Рассмотрим простейший пример: вы ввели некоторый url в адресную строку. Поехали.
The Open Systems Interconnection model (OSI)
Для начала придётся упомянуть семиуровневую модель OSI, с которой, возможно, каждый из вас знаком не понаслышке. Эталонная модель взаимодействия открытых систем является абстракцией, которая связывает и стандартизирует взаимодействие открытых систем. Она не описывает никакие используемые протоколы, а только определяет, какие функции выполняет каждый из её уровней. В основе любого сетевого взаимодействия лежит данная модель. Для привычного нам интернета схема OSI и соответствующие ей протоколы чаще всего имеют следующий вид:
Эталонная модель OSI и соответствие ей протоколов Интернета
Некоторые уровни могут отсутствовать и/или объединяться. Рассматривать работу схемы начнём с верхнего уровня — с того самого ввода адреса в адресную строку.
Уровень представления, SSL (TLS)
Уровень представления отвечает за кодирование/декодирование, а также за шифрование/дешифрование данных. Благодаря этому уровню информация, передаваемая одной системой, всегда понятна другой системе.
Транспортный уровень, TCP
Формируются TCP-пакеты чаще всего в ядре операционной системы. Вся прелесть протокола TCP — в надёжности доставки. Использование этого протокола предусматривает установление так называемого логического соединения между двумя конечными узлами сети (перед этим, естественно, такое соединение нужно согласовать). Надёжную доставку пакетов протокол TCP обеспечивает посредством нумерации пакетов, подтверждения их передачи квитанциями, а также контроля правильного порядка пакетов. Схема установления логического соединения, передачи данных и разрыва соединения представлена на рисунке ниже:
Работа хостов с помощью логического соединения
Сетевой уровень, IP
Сетевой уровень в общем случае нужен для образования единой транспортной системы, которая объединяет несколько сетей. Сети, кстати, могут иметь разные стеки протоколов. Также на этом уровне определяется маршрут пересылки пакетов от отправителя к получателю.
По ходу перемещения IP-пакета по сети маршрутизаторы передают пакеты от одной сети к другой или же на конечный узел-получатель. Данный протокол не занимается установлением соединения, не контролирует целостность данных, не гарантирует доставку и не отвечает за их достоверность, то есть реализует политику доставки "по возможности". Всё это бремя возложено на вышележащий протокол — TCP. Получив TCP-пакет, ОС инкапсулирует его в IP-пакет, добавляет в него свои параметры и передаёт далее.
UDP-дейтаграмма инкапсулируется в IP-пакет данных с IP-адресом назначения DNS-сервера и отправляется на DNS-сервер.
DNS-сервер возвращает запись ресурса, в которой указан IP-адрес URL.
Физический и канальный уровни, Ethernet
Канальный уровень (также — уровень передачи данных) необходим для передачи сырых данных физического уровня по надежной линии связи. Основная задача на этом уровне — обнаружение и коррекция ошибок. Также он может исправлять ошибки за счёт повторной передачи поврежденных кадров. Канальный уровень тоже должен проверить доступность среды — можно ли выполнять пересылку данных в конкретный момент. Иногда эту функцию выделяют в отдельный подуровень управления доступом к среде (MAC).
Физический уровень отвечает за передачу потока битов по каналам физической связи (коаксиальные кабеля, оптоволокно, витая пара). Со стороны компьютера функции физического уровня выполняет сетевой адаптер или COM-порт. На этом уровне есть только поток битов и ничего более: протокол "не задумывается" об информации, которую он передаёт.
В нашем случае протокол Ethernet объединяет эти два уровня. Ethernet оперирует единицей данных, которая называется кадр. Для физического уровня нет никакого анализа информации, которая передаётся. Для передачи данных между узлами протокол работает по схеме с коммутацией пакетов, то есть сеть ведёт себя менее "ответственно", не создавая для абонентов отдельных каналов связи. Данные могут задерживаться и даже теряться. Поэтому ошибки на этом уровне не исправляются. Это опять же возложено на протокол верхнего уровня — TCP.
Для физического уровня Ethernet описывается стандартом группы IEEE 802.3, который определяет физические характеристики канала связи. Например, какой кабель будет использоваться для передачи данных: витая пара, коаксиальный кабель или оптоволокно. Тут же определяется вид кодирования и модуляции сигнала. Технические характеристики каждого стандарта хорошо описаны в данной статье. Например, спецификация 100Base-T определяет в качестве используемого кабеля витую пару, с максимальной длинной физического сегмента 100 метров и манчестерским кодом для данных в кабеле.
Путь пакета
На следующей схеме представлена схема взаимодействия узлов сети. Наш пакет выходит из конечного узла слева, проходя через концентраторы, коммутаторы (работающие на канальном уровне) и маршрутизаторы, работающие на сетевом уровне:
Общая схема взаимодействия узлов сети
Как видно из схемы, концентратор работает с данными на физическом уровне, но в настоящее время они вытеснены сетевыми коммутаторами, умеющими работать на канальном и физическом уровнях.
Книги, которые помогли мне. Рекомендую и вам:
Олифер В.Г., Олифер Н.А. Компьютерные сети. Принципы, технологии, протоколы - СПб.: Питер, 2018. - 992
Таненбаум Э., Уэзеролл Д. Компьютерные сет - СПб.: Питер, 2020. - 960 с.: ил.
Браузер и веб-сервер
Для базового понимания работы веба можно провести аналогию с телевидением.
Браузеры — Google Chrome, Firefox, Safari, Internet Explorer / Edge — это всего лишь экраны телевизоров, которые показывают программу, записанную и транслируемую откуда-то из далёких телестудий. В вебе такие студии называются веб-серверами.
Вбивая новый адрес в браузере, вы переключаете канал. Только в отличие от телевидения в интернете этих каналов огромное количество, вы даже можете создать свой, настроив собственный веб-сервер.
У каждого веб-сервера подобно телеканалу есть свой номер, который называется IP. Чаще всего он выглядит как четыре группы трёхзначных чисел, разделённых точкой — XXX.XXX.XXX.XXX, но может выглядеть иначе — см. IPv6.
Например, Вконтакте имеет IP 87.240.137.158, Facebook — 31.13.72.36, данный блог — 5.63.155.79.
Поскольку таких пар «IP — домен» по всему интернету огромное количество, то браузер не может все их знать и поэтому он обращается за помощью к DNS-серверу, который работает как адресная книга — по домену выдаёт IP, на который нужно слать запросы, и перенаправляет запрос на нужный веб-сервер в интернете.
Получив запрос от браузера, веб-сервер отправляет в ответ запрошенную веб-страницу или ошибку, если что-то пошло не так.
Если такой страницы не существует, браузер покажет ошибку.
Из чего состоит веб-страница
Веб-страница — это то, что вы видите в браузере. Она представляет собой HTML — обычный текст, но помещённый в специальные символы — «теги», подсказывающие браузеру, где заголовки и списки, а где картинки, формы для пользовательского ввода и, конечно же, ссылки на другие страницы. Ссылки — они же гипертекс — в своё время и сделали веб таким удобным и популярным.
Вы можете посмотреть из чего состоит любая веб-страница, кликнув по ней в браузере правой кнопкой мыши и выбрав пункт View Page Source / Посмотреть исходную страницу или что-то аналогичное в зависимости от браузера и языка интерфейса. Скорее всего вы ничего не поймёте, так как помимо HTML-разметки современные веб-страницы включают в себя кучу CSS и Javascript. Первая технология позволяет создавать красивый вид страниц (дизайн), а вторая — анимировать их и расширять функционал: всплывающие окна, проигрыватели аудио и видео, слайдеры, счётчики, метрики, обработка картинок, анимированная галерея фотографий и много чего ещё.
Кратко:
HTML — это разметка статического контента, задание его структуры
CSS — наведение красоты, включая простую анимацию
Javascript — более сложная анимация и дополнительный функционал поверх контента
Вы можете создавать свои веб-страницы прямо у себя на компьютере. Но чтобы другие люди их увидели, вам нужен веб-сервер, доступный через интернет. Попробуйте создать на своём компьютере файл index.html (скачать готовый пример), внутри которого написать
Сохраните и перетащите файл прямо в браузер — вы увидите ваш первый, хоть и не публичный, сайт.
Статические и динамические страницы
Все веб-страницы можно условно разделить на два вида — статичные и динамичные.
- Статичные — это уже готовый HTML, CSS, Javascript, который веб-сервер сразу же отдаёт по запросу браузера. Пример с index.html выше является статичной страницей. Её контент зафиксирован и будет отображаться одинаково для всех браузеров.
- Динамичные (и их сейчас большинство) страницы можно представить себе как шаблоны итоговых страниц, но с вкраплениями серверного кода. Такой код при выполнении может проверять авторизован пользователь или нет, обращаться к базе данных или сторонним сервисам (например, за курсом валют) и даже полностью менять содержимое страницы, но в конечном итоге он всё равно превращается в HTML, CSS и Javascript, которые веб-сервер отдаёт браузеру.
Браузеру вся эта кухня не видна, он лишь делает запрос и получает в ответ HTML, CSS и Javascript. Каждый клик по ссылке или отправка формы делает новый запрос на веб-сервер, который начинает весь процесс заново.
Чтобы посмотреть на запросы, которые отправляет ваш браузер и что он получает в ответ, можно воспользоваться инструментом инспекции кода в браузере. Правый клик в любом месте страницы, выберите пункт «Inspect / Инспектировать элемент» или подобный, а потом перейдите в таб «Netword / Сеть». Перезагрузите страницу и вы увидите, как браузер общается с веб-сервером (или даже несколькими).
Читайте также: