В предыдущем параграфе вы узнали, как работает интернет и что он состоит из клиентов и серверов.
В этом параграфе мы переместимся в одну из частей интернета — в веб, где за передачу данных отвечает протокол HTTP. Мы рассмотрим:
- Как устроено взаимодействие клиентов и серверов.
- Что такое API и зачем они нужны программистам.
- Какие бывают API.
Приступим!
Что произошло, когда вы открыли эту страницу
Ваш браузер — клиент — самостоятельно не умеет подключаться к серверу: для этого нужно «железо» (например, сетевая карта или Wi-Fi-модуль) и операционная система (ОС).

Поэтому браузер обращается к ОС и говорит: «Нужно получить данные, которые лежат по адресу https://education.yandex.ru/handbook. Дай, пожалуйста, IP».
Операционная система отправляет запрос к DNS-серверу — чаще всего интернет-провайдера, — чтобы узнать IP-адрес сайта. Если он неизвестен, она отправляет запросы к более «высоким» DNS-серверам, пока наконец не получит ответ.
ОС получила IP. Она передаёт его браузеру. Браузер снова просит её: «Подключись к серверу на этом IP, порт 443, протокол HTTPS». HTTPS — более защищённая версия HTTP.
Но ОС не может просто так заявиться к серверу и сказать: «А ну-ка дай мне данные!» — как и мы не можем написать в ЗАГС «Дайте справку». Надо составить обращение по установленной форме — запрос. Как мы уже знаем, форму обращения определяет протокол HTTP. Как доставить данные — протокол TCP.
ОС формулирует запрос к серверу и с помощью сетевого стека разбивает его на пакеты — пронумерованную последовательность битов. Затем она с помощью сетевой карты обращается к ОС сервера и предлагает установить соединение. Для этого они обмениваются тремя сообщениями:
— Привет! Хочу получить данные, буду отправлять запрос. Номер моего первого пакета — 100, размер — 10 байт. Порт — 443, протокол — HTTPS.
— Привет! Номер записал. Номер моего ответного пакета будет 500. Устанавливаем соединение?
— Номер записал. Подтверждаю, устанавливаем.
Этот процесс называется TCP Handshake. Три сообщения (SYN, SYN-ACK, ACK) позволяют синхронизировать взаимные ожидания и установить надёжную связь, чтобы в случае сбоя при отправке-получении пакета не нужно было начинать процесс обмена данным с самого начала.
Продолжим. Мы используем протокол HTTPS. Это значит, что сервер и клиент не могут просто так начать обмениваться данными. Поэтому клиент говорит:
— Чуть не забыл. Хочу проверить, что вы точно не мошенник. Вот перечень шифров и случайное число. Выбирайте.
— Нет, что вы, ну какой мошенник! Выбираю такой-то шифр и вот моё случайное число. И кстати, у меня ещё сертификаты есть!
Клиент изучает сертификат: не просрочен ли, кем выдан, соответствует ли домену и так далее. И продолжает:
— Да, всё в порядке. С помощью шифра и наших чисел я кое-что зашифровал. Расшифруйте их и скажите, что у вас получилось.
Расшифровывает и называет.
— Всё верно! Давайте обменяемся секретными ключами.
— По рукам.
Этот процесс называется TLS Handshake (Transport Layer Security), и он гарантирует, что злоумышленники не смогут перехватить ваши данные и от вашего имени обратиться к серверу, например, чтобы перевести деньги на свой счёт. Поэтому HTTPS-протокол безопаснее, чем HTTP.
Продолжим. Соединение установлено, ваша сетевая карта начинает отправлять пакеты, сетевая карта севера получает их. Операционная система сервера с помощью сетевого стека распаковывает их и собирает вместе. Передаёт их в программу-сервер.
После расшифровки HTTPS-соединения программа-сервер получает «обычный» HTTP-запрос. По порту и протоколу она понимает, что нужно передать его веб-серверу, а не, например, почтовому. Веб-сервер получает запрос, изучает и принимает решение, как на него отвечать.
Поскольку мы запрашиваем данные, это будет GET-запрос. В ответ на GET-запрос сервер N отвечает данными, если они у него есть, конечно. Или ошибкой, если данных нет. Но раз вы читаете эту страницу, всё в порядке!
Далее веб-сервер обращается к ОС сервера: «Хочу ответить на запрос. Вот данные!» ОС разбивает их на пакеты и через сетевую карту отправляет клиенту.
Сетевая карта клиента получает пакеты и передаёт в ОС. Та собирает их в правильной последовательности и передаёт браузеру. Браузер начинает рендеринг, то есть вывод содержимого сайта на экран.
Браузер получил только HTML — описание, из каких элементов состоит страница. Он сканирует это и смотрит, нет ли там ссылок. Видит ссылку на CSS-документ (описание, как должны выглядеть элементы на странице).
Браузеру нужно получить эти данные. Он снова просит ОС сделать запрос… Да, шаги выше повторяются. Да, для каждого вида данных: картинок, JS-кода, шрифтов и так далее.
Затем браузер отрисовывает страницу. Как это происходит в деталях, рассказывать не будем, иначе закопаемся. Коротко отметим, что это происходит в несколько этапов:
- Загрузка данных (это мы выполнили).
- Преобразование HTML и CSS для удобной работы с ними.
- Расчёт размеров, позиции и взаиморасположения элементов на экране в зависимости от его размеров.
- Стилизация элементов: применение цветов, теней, анимаций.
- Смешивание слоёв.
А в деталях?
Целиком — от получения HTML и CSS и до того, как страница отобразится на экране, — процесс называется Critical Rendering Path. Он включает парсинг, стилизацию, рендер и отрисовку.
Подробнее обо всех нюансах и этапах можно прочитать по ссылке.
Пока страница отрисовывается, исполняется JavaScript-код. Например, он может побудить браузер запросить у сервера дополнительные данные. В случае нашей страницы это будет информация, прочитан параграф или нет.
И когда сервер ответит — браузер заново выполнит шаги 3, 4 и 5, чтобы актуализировать информацию.
В идеальных условиях: небольшой сайт, высокая скорость соединения, мощное железо на клиенте и сервере — все процессы займут от 1 до 3 секунд. Просто невероятно быстро, учитывая, сколько действий потребовалось совершить! И это мы их очень схематично описали, потому что под фразой «исполняется JavaScript-код» скрывается ещё несколько десятков операций.
И ещё несколько сотен, если добавить взаимодействие браузера, дисплея и видеокарты.
Очень важная ремарка
Почти на каждом этапе происходит проверка кэша, то есть локальных хранилищ, в которых могли сохраниться какие-то данные, если пользователь уже посещал сайт.
Браузер ищет сохранённые CSS, картинки, JS.
ОС может использовать DNS-кэш, чтобы не запрашивать IP-адрес заново.
Это нужно, чтобы не тратить время на вычисления того, что уже было вычислено. То есть чтобы сайт открывался как можно быстрее и вы не грустили. Потому что иначе провести все вот эти вот сложные вычисления и запросы и уложиться в 1–3 секунды нереально.
Поэтому телефоны иногда приходится очищать от устаревших кэшированных данных — это и называют «мусором».
Если подытожить: есть заранее согласованные правила, по которым общаются клиент и сервер. Эти правила могут сильно различаться в зависимости от специфики конкретного приложения.
API
API расшифровывается как Application Programming Interface — интерфейс программирования приложения. Если на пальцах: это правила и инструменты, с помощью которых одна программа может общаться с другой.
В примере выше API — все возможные URL, по которым браузер (клиент) может общаться с сервером.
Запросы на одни URL возвращают HTML-разметку, на другие — только данные. Вы это могли увидеть выше, когда JavaScript попросил браузер сбегать за данными о том, просмотрен параграф или нет.
Браузер мог отправить запрос на https://education.yandex.ru/handbook/is-paragraph-done. Только в ответ он получит не HTML и прочий контент, а true, если параграф прочитан, и false — если нет. Такой адрес бесполезно открывать в браузере: вы ничего не увидите.
Поведение, как реагировать на запрос клиента, определяет бэкенд-разработчик, который программировал веб-сервер. Собственно, он и решает, какие URL будут возвращать HTML, а какие — работать с данными.
Мы не случайно говорим «работать», потому что клиент может не только запрашивать данные, но и модифицировать их.
Для организации API часто используется подход под названием REST — передача репрезентативного состояния. REST добавляет разные типы команд, которые могут быть вызваны.
- GET — запрос данных.
- POST — отправка новых данных.
- PUT — изменение данных.
- DELETE — удаление данных.
Предположим, у нас есть ещё один клиент, который работает с сайтом хендбуков. Это компьютер контент-менеджера Ильи, который заходит в секретный раздел сайта — админ-панель. С её помощью он загружает новые параграфы, редактирует существующие и удаляет ненужные.
Илье надо опубликовать в хендбуке новый параграф в третьей главе. Он откроет админку, перенесёт текст, сделает другие необходимые действия и нажмёт кнопку «Опубликовать». И на веб-сервер отправится запрос.
POST /computer-science-handbook/3/6
Веб-сервер примет его, изучит, корректные ли данные переданы, выберет нужные (например, текст параграфа) и отправит запрос в базу данных: «Найди хендбук с ID = computer-science-handbook, в нём — главу с ID = 3, создай в ней параграф с ID = 6 и сохрани в нём текст».
А если данные некорректны?
Тогда бэкенд вернёт клиенту ошибку. А ещё он вернёт ошибку, если, например, база данных не сможет найти такой хендбук, или главу, или параграф.
Задача программиста, который писал веб-сервер, — продумать все возможные сценарии и настроить отправку корректных ошибок. А задача программиста, который писал админку для Ильи, — настроить приём ошибок и выдачу их в человекочитаемом формате.
Если это были хорошие программисты, то Илья увидит всплывающее уведомление: «Невозможно создать параграф: хендбук computer-science-handbook не существует». Или: «Невозможно создать параграф: главы 3 не существует».
А если он увидит просто текст Error или просто белый экран — значит, кто-то из программистов поленился!
Пройдёт пара дней. Внимательный читатель заметит какую-то ошибку в тексте, и Илье придёт уведомление. Он снова откроет админку, внесёт изменения и снова нажмёт «Опубликовать». И тогда на веб-сервер отправится запрос:
PUT /computer-science-handbook/3/6
Веб-сервер сделает всё то же самое, что и выше, только отправит в базу данных другой запрос: «Найди хендбук с ID = computer-science-handbook, в нём — главу с ID = 3, в ней — параграф с ID = 6 и обнови в нём текст».
А как браузер поймёт, когда отправлять PUT, а когда POST?
Ему подскажет разработчик, который писал веб-админку.
Например, перед отправкой запроса о публикации параграфа будет код, в котором сначала отправится запрос:
GET /computer-science-handbook/3/6
И дальше решение будет приниматься от результата. Если запрос успешный, значит, параграф уже есть и нужно отправить PUT, чтобы его изменить. Если ошибочный — нужно отправлять POST.
Пройдёт время, глава станет неактуальной. Тогда Илья по традиции откроет админку и нажмёт кнопку «Удалить». На веб-сервер отправится запрос:
DELETE /computer-science-handbook/3/6
Ну а что будет дальше — вы уже и так знаете.
Сейчас коротко остановимся и проговорим одну важную вещь:
API позволяет работать с клиентами разных типов.
Например, Илья обновляет параграф через админку на веб-сайте. Но какой-нибудь заботливый программист может написать приложение для Android, которое будет работать с API хендбуков: отправлять запросы на те же URL. Другой программист напишет программу для Windows или macOS.
Как они будут устроены, нам неважно, — это детали реализации. Важно, что они будут работать, потому что эти приложения (клиенты) всего лишь отправляют HTTP-запросы по специальным URL, которые определяются API.
API-протоколы

Выше мы рассмотрели, как организуется API c помощью протокола HTTP. Как вы понимаете, это не единственный способ. Далее коротко рассмотрим некоторые:
- WebSocket
- RPC
- MQTT
- Вебхуки
Пусть вас не пугают аббревиатуры, просто держите в голове, что у каждой из них есть свои плюсы и минусы, которые определяют, в каких ситуациях использовать тот или иной протокол.
Вот, например, HTTP. Он самый простой, но не подходит для обмена данными в реальном времени, потому что работает в формате «запрос — ответ»: чтобы взаимодействие с сервером было в реальном времени, нужно каждые X секунд запрашивать данные и тут же публиковать свои.
А если изменений нет — получается, весь тот путь, который проходит запрос до сервера, был напрасным.
Для таких целей умные люди придумали другой протокол — WebSocket.
WebSocket
Суть простая: клиент и сервер устанавливают непрерывную связь и обмениваются сообщениями.
Этот протокол подходит, когда приложению необходим постоянный обмен данными и требуется быстрая реакция. Самый подходящий пример — чаты. Клиент подключается к серверу и по этому каналу получает обновление: «Есть новое сообщение для тебя» — и отправляет туда же свои сообщения для другого клиента.
RPC
Он же «удалённый вызов процедуры», используется для более сложных ситуаций. Взаимодействует с разными серверами и выполняет команду так, как если бы она работала у клиента. Обычно это используется, когда вместе с командой надо передавать большой контекст, а также для ускорения.
Ключевое отличие RPC от HTTP в том, что в RPC мы напрямую вызываем нужную функцию с параметрами и так же, напрямую, получаем результат. А в HTTP под конкретным запросом может скрываться много проверок.
MQTT
Работает по принципу «издатель и подписчик». Чаще всего его можно встретить в инфраструктуре «умного дома» для общения между устройствами.
Есть сервер, который называется «брокер». Сами устройства вроде датчиков и розеток являются «издателями», они отсылают данные о своём состоянии. «Брокер» собирает из них очереди и ждёт, когда к нему придут последние участники, «клиенты-подписчики», чтобы отдать им данные. Примером такого «подписчика» может быть система рисования графиков температуры в доме, она будет запрашивать у «брокера» данные о температуре.
Вебхуки
Или их ещё называют WebHooks. В этом случае клиент сначала отсылает серверу сообщение: «Я вот тут. Если что-то произойдёт, расскажи об этом» — и просто ждёт.
А когда нужное событие наступает, сервер присылает сообщение по указанному адресу. Например, так может быть организована работа ботов в чатах. Приложение бота подключено, но ничего не делает до тех пор, пока бота не упоминают. Сервер может прислать боту сообщение: «Эй, про тебя спрашивали», и тогда бот начнёт выполнять свои задачи.
Вот и всё! Мы разобрали основные концепции клиент-серверного взаимодействия и связали всё воедино: как они общаются между собой и за что отвечает браузер/приложение, а за что — операционная система и железо.
Теперь, если страница долго не загружается, вы не будете сердиться, зная, какой путь сейчас проходит ваш запрос. На этом вторая глава заканчивается, в следующем параграфе подведём итоги.
