Лекция 4. Прикладные протоколы и форматы данных
Введение
В предыдущих лекциях мы рассмотрели сетевые основы интернет-приложений и базовый протокол прикладного уровня — HTTP. Однако современный backend редко ограничивается «голым» HTTP. Данные нужно передавать защищённо, иногда — в реальном времени, между сервисами — быстро и типобезопасно. А ещё их нужно во что-то упаковать: в JSON, XML, HTML или бинарный формат.
В этой лекции мы разберём:
- HTTPS и TLS — зачем нужно шифрование и как устроено защищённое соединение (обзорно);
- WebSocket — протокол двусторонней связи для приложений реального времени;
- gRPC — высокопроизводительный RPC поверх HTTP/2 и Protobuf (обзорно);
- форматы данных — JSON (основной для API), XML, HTML и другие;
- сериализацию и десериализацию — как объект превращается в байты и обратно;
- сетевую безопасность — основные угрозы и защита (кратко);
- оптимизацию — кеширование и сжатие (кратко).
Цель — научиться осознанно выбирать протокол и формат под конкретную задачу.
1. HTTPS и TLS
1.1. Зачем нужно шифрование
Обычный HTTP передаёт данные открытым текстом. Любой узел на пути между клиентом и сервером (Wi-Fi-точка, провайдер, прокси) может прочитать или изменить трафик. Это недопустимо для паролей, токенов, платёжных данных и персональной информации.
HTTPS (HTTP Secure) решает проблему: это тот же HTTP, но передаваемый внутри защищённого канала, который создаёт протокол TLS (Transport Layer Security). TLS — преемник устаревшего SSL; сегодня актуальны версии TLS 1.2 и TLS 1.3.
HTTPS обеспечивает три гарантии безопасности:
- Конфиденциальность — данные зашифрованы, посторонний видит лишь поток случайных байтов.
- Целостность — попытка изменить данные «на лету» будет обнаружена.
- Аутентификация — клиент убеждается, что общается с настоящим сервером, а не с подменным (через сертификат).
1.2. TLS-рукопожатие (обзорно)
Прежде чем передать первый байт HTTP, клиент и сервер выполняют TLS handshake — согласование параметров защищённого соединения. Упрощённо:
- ClientHello — клиент сообщает поддерживаемые версии TLS и наборы шифров (cipher suites).
- ServerHello + сертификат — сервер выбирает параметры и присылает свой TLS-сертификат, выпущенный удостоверяющим центром (CA). Клиент проверяет, что сертификат подлинный и выдан именно для этого домена.
- Обмен ключами — стороны с помощью асимметричной криптографии безопасно договариваются об общем секретном ключе.
- Готово — дальше весь HTTP-трафик шифруется быстрым симметричным алгоритмом (например, AES) этим общим ключом.
Ключевая идея: асимметричное шифрование (медленное) используется только для безопасного обмена ключом, а основной обмен данными идёт симметричным шифрованием (быстрым). В TLS 1.3 рукопожатие ускорено и требует меньше «кругов» по сети.
Для разработчика backend важно понимать: HTTPS — это стандарт де-факто. Современные браузеры помечают сайты без HTTPS как небезопасные, а многие возможности (Service Workers, геолокация) доступны только по HTTPS. На продакшене TLS обычно «терминируется» на reverse-proxy (nginx) или балансировщике.
2. WebSocket
2.1. Проблема: HTTP однонаправлен
HTTP построен на модели «запрос — ответ»: инициатором всегда выступает клиент, сервер только отвечает. Сервер не может сам «толкнуть» данные клиенту. Для чатов, уведомлений и биржевых котировок это неудобно — раньше приходилось применять костыли вроде постоянного опроса (polling) сервера.
WebSocket — протокол полнодуплексной (двусторонней) связи поверх одного TCP-соединения. После установки соединения и клиент, и сервер могут отправлять сообщения в любой момент.
2.2. Как устанавливается соединение
WebSocket «вырастает» из обычного HTTP-запроса:
- HTTP Upgrade — клиент отправляет запрос с заголовком
Upgrade: websocket. - Handshake — сервер отвечает кодом
101 Switching Protocols, подтверждая переключение протокола. - Обмен фреймами — соединение остаётся открытым, стороны обмениваются сообщениями (фреймами) с минимальными накладными расходами.
GET /ws HTTP/1.1Host: chat.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==Sec-WebSocket-Version: 132.3. Когда нужен WebSocket
Применяйте WebSocket, когда данные должны приходить от сервера по инициативе сервера и в реальном времени:
- чаты и мессенджеры;
- онлайн-игры;
- биржевые котировки и торговые терминалы;
- совместное редактирование документов;
- дашборды мониторинга и live-уведомления.
Если же клиент просто запрашивает данные время от времени — достаточно обычного HTTP. Не используйте WebSocket там, где хватает «запрос — ответ»: постоянное соединение расходует ресурсы сервера. FastAPI поддерживает WebSocket «из коробки» через декоратор @app.websocket(...).
3. gRPC
3.1. Идея RPC
RPC (Remote Procedure Call, удалённый вызов процедур) — подход, при котором вызов функции на другом сервере выглядит для программиста почти как вызов обычной локальной функции. Детали сети скрыты.
gRPC — современный RPC-фреймворк от Google. Его три кита:
- HTTP/2 как транспорт — мультиплексирование нескольких вызовов в одном соединении, сжатие заголовков, потоковая передача.
- Protocol Buffers (Protobuf) — компактный бинарный формат сериализации и язык описания интерфейсов (IDL).
- Генерация кода — по описанию
.protoавтоматически создаётся клиентский и серверный код для многих языков.
3.2. Описание сервиса
Контракт сервиса описывается в .proto-файле:
syntax = "proto3";
service UserService { rpc GetUser (UserRequest) returns (User);}
message UserRequest { int32 id = 1;}
message User { int32 id = 1; string name = 2; string email = 3;}Из этого файла генерируются типобезопасные клиент и сервер. Числа (= 1, = 2) — это теги полей, обеспечивающие совместимость версий.
3.3. Типы вызовов и применение
gRPC поддерживает четыре вида взаимодействия:
- Unary — один запрос, один ответ (как обычный вызов функции);
- Server streaming — один запрос, поток ответов;
- Client streaming — поток запросов, один ответ;
- Bidirectional streaming — потоки в обе стороны.
Где применяют: связь между микросервисами внутри инфраструктуры, системы реального времени, IoT. gRPC быстрее и компактнее REST/JSON за счёт бинарного формата, но менее удобен для отладки (бинарь не прочитать глазами) и хуже работает напрямую из браузера. Поэтому типичный выбор: REST/JSON наружу (для публичного API и фронтенда) и gRPC внутри (между сервисами).
4. Форматы данных
Данные, которыми обмениваются клиент и сервер, нужно представить в виде, понятном обеим сторонам. Выбор формата влияет на читаемость, размер, скорость обработки и совместимость.
4.1. JSON — основной формат API
JSON (JavaScript Object Notation) — лёгкий текстовый формат, сегодня это стандарт де-факто для REST API.
{ "id": 123, "name": "John Doe", "age": 30, "isActive": true, "address": { "city": "New York", "zipCode": "10001" }, "hobbies": ["reading", "coding"], "spouse": null}Поддерживаемые типы данных:
- string — строка в двойных кавычках;
- number — целое или вещественное число;
- boolean —
true/false; - null — отсутствие значения;
- object — набор пар «ключ — значение» в
{ }; - array — упорядоченный список в
[ ].
Достоинства: читается человеком, компактнее XML, быстро парсится, поддерживается всеми языками, нативен для JavaScript.
Ограничения: нет комментариев, нет встроенных типов для дат и бинарных данных (дату передают строкой в формате ISO 8601), нет встроенной схемы. Для описания структуры используют JSON Schema; в FastAPI это решается через модели Pydantic, которые валидируют входящий JSON автоматически.
4.2. XML
XML (eXtensible Markup Language) — расширяемый язык разметки. Те же данные:
<?xml version="1.0" encoding="UTF-8"?><user id="123"> <name>John Doe</name> <age>30</age> <address> <city>New York</city> <zipCode>10001</zipCode> </address> <hobbies> <hobby>reading</hobby> <hobby>coding</hobby> </hobbies></user>Особенности: строгая валидация по схемам (DTD, XSD), пространства имён, мощные языки запросов (XPath, XQuery), атрибуты у элементов. Минусы: многословность, больший объём, медленнее парсится. XML по-прежнему встречается в корпоративных системах (протокол SOAP), форматах RSS/Atom и конфигурационных файлах, но в новых веб-API почти вытеснен JSON.
4.3. HTML
HTML (HyperText Markup Language) — язык разметки для представления страниц в браузере. В отличие от JSON и XML, он предназначен не для обмена данными между программами, а для отображения контента человеку.
<!DOCTYPE html><html lang="ru"><head> <meta charset="UTF-8"> <title>Страница</title></head><body> <h1>Заголовок</h1> <p>Текст параграфа</p></body></html>Backend может либо отдавать готовый HTML (рендеринг на сервере, например через шаблонизатор Jinja2), либо отдавать JSON, а HTML формировать на стороне клиента (SPA). В современном HTML5 важны семантические теги (<header>, <nav>, <main>, <article>, <footer>), делающие структуру понятной.
4.4. Другие форматы (кратко)
- YAML — человекочитаемый формат для конфигов и CI/CD (отступы вместо скобок). Удобен людям, но чувствителен к форматированию.
- Protocol Buffers — бинарный типизированный формат от Google, основа gRPC. Компактнее и быстрее JSON, но не читается глазами.
- MessagePack — бинарный «JSON в сжатом виде» для высоконагруженных систем.
- Мультимедиа — изображения (JPEG, PNG, SVG, WebP), видео (MP4, WebM), аудио (MP3, AAC, Opus). Передаются как бинарные данные с соответствующим
Content-Type.
4.5. Сравнение форматов
| Критерий | JSON | XML | Protobuf |
|---|---|---|---|
| Представление | текст | текст | бинарь |
| Читаемость для человека | высокая | средняя | нет |
| Размер | средний | большой | минимальный |
| Скорость обработки | высокая | низкая | очень высокая |
| Схема/валидация | внешняя (JSON Schema) | встроенная (XSD) | встроенная (.proto) |
| Типичное применение | REST API | корпоративные системы, SOAP | gRPC, микросервисы |
5. Сериализация и десериализация
В памяти программы данные хранятся как объекты (например, экземпляр класса User в Python). Чтобы передать их по сети, нужно превратить объект в последовательность байтов — это сериализация (или маршалинг). Обратный процесс на принимающей стороне — десериализация: из байтов восстанавливается объект.
Объект в памяти --сериализация--> байты (JSON/XML/Protobuf) --сеть--> <--десериализация-- байты <--Простой пример на Python со стандартным JSON:
import json
user = {"id": 123, "name": "John", "is_active": True}
# Сериализация: объект -> строка JSONtext = json.dumps(user) # '{"id": 123, "name": "John", "is_active": true}'
# Десериализация: строка JSON -> объектobj = json.loads(text) # {'id': 123, 'name': 'John', 'is_active': True}В FastAPI сериализация и десериализация в основном выполняются автоматически: входящий JSON-запрос разбирается и валидируется в модель Pydantic, а возвращаемый объект сериализуется обратно в JSON. Это снимает с разработчика рутину и снижает число ошибок.
Важно помнить о соответствии типов: например, дату в JSON передают строкой, а при десериализации преобразуют обратно в объект даты. Несогласованность форматов — частый источник ошибок интеграции.
6. Сетевая безопасность (кратко)
Безопасность — обязательная часть проектирования backend. Рассмотрим основные категории угроз и защиту от них.
6.1. Основные угрозы
- Перехват трафика (sniffing) — пассивное прослушивание сети, кража паролей и токенов. Защита: шифрование (TLS/HTTPS).
- Подмена данных и Man-in-the-Middle — злоумышленник встраивается между сторонами, изменяет трафик или выдаёт себя за сервер. Защита: TLS-сертификаты, цифровые подписи, проверка целостности.
- DoS / DDoS — перегрузка сервера лавиной запросов до отказа в обслуживании. Защита: ограничение частоты запросов (rate limiting), балансировка, фильтрация трафика, CDN.
6.2. Практические меры
- HTTPS везде — базовая мера; заголовок
Strict-Transport-Securityпринуждает браузер всегда использовать HTTPS. - Заголовки безопасности —
Content-Security-Policy(защита от внедрения скриптов),X-Frame-Options(защита от clickjacking),X-Content-Type-Options: nosniff. - Аутентификация и авторизация — JWT (самодостаточные подписанные токены), OAuth 2.0 (делегированный доступ), OpenID Connect (стандартная аутентификация поверх OAuth).
- Валидация входных данных — никогда не доверять данным от клиента; проверять и очищать всё, что приходит снаружи (в FastAPI помогает Pydantic).
7. Оптимизация (кратко)
Быстрый отклик напрямую влияет на пользовательский опыт. Две самые доступные техники — кеширование и сжатие.
7.1. Кеширование
Кеширование избавляет от повторного выполнения дорогих операций и повторной передачи неизменившихся данных.
- На клиенте — браузерный кеш, локальное хранилище.
- На сервере и в сети — CDN (географически распределённые серверы отдают статику ближе к пользователю), reverse-proxy, кеш на уровне приложения (например, Redis).
- Управление через заголовки HTTP:
Cache-Control: public, max-age=3600ETag: "abc123"Last-Modified: Wed, 21 Oct 2015 07:28:00 GMTЗаголовки ETag и Last-Modified позволяют клиенту сделать условный запрос: если ресурс не изменился, сервер отвечает 304 Not Modified с пустым телом, экономя трафик.
7.2. Сжатие
Текстовые данные (HTML, JSON, CSS, JS) хорошо сжимаются перед передачей:
- Gzip — повсеместно поддерживается, экономит до ~70 % объёма;
- Brotli — современный алгоритм, сжимает текст ещё эффективнее.
Клиент сообщает поддержку заголовком Accept-Encoding: gzip, br, сервер отвечает Content-Encoding: gzip. Сжатие обычно настраивается на reverse-proxy и почти не требует усилий со стороны разработчика, давая заметный выигрыш.
Современные версии протокола (HTTP/2 и HTTP/3) сами по себе ускоряют обмен за счёт мультиплексирования потоков и сжатия заголовков.
8. Сравнение протоколов
| Критерий | HTTP | WebSocket | gRPC |
|---|---|---|---|
| Модель связи | запрос — ответ | полный дуплекс | RPC (вызов процедур) |
| Инициатор | клиент | обе стороны | клиент (есть стриминг) |
| Транспорт | TCP (HTTP/1.1, /2) | TCP | HTTP/2 |
| Формат данных | любой (обычно JSON) | любой | Protobuf (бинарь) |
| Реальное время | нет | да | частично (стриминг) |
| Читаемость | высокая | зависит | низкая (бинарь) |
| Типичное применение | REST API, веб | чаты, live | связь микросервисов |
Краткие итоги
- HTTPS = HTTP внутри TLS. Шифрование даёт конфиденциальность, целостность и аутентификацию сервера. Рукопожатие согласует параметры: асимметричная криптография — для обмена ключом, симметричная — для основного трафика. HTTPS сегодня обязателен.
- WebSocket — двусторонняя связь поверх одного TCP-соединения, устанавливается через HTTP Upgrade (
101 Switching Protocols). Нужен для реального времени: чаты, котировки, уведомления. Где хватает «запрос — ответ» — он избыточен. - gRPC — RPC поверх HTTP/2 с бинарным Protobuf и генерацией кода. Быстр и типобезопасен, удобен между микросервисами; снаружи обычно остаётся REST/JSON.
- Форматы: JSON — основной для API (читаемый, универсальный); XML — корпоративные системы; HTML — отображение для человека; Protobuf/MessagePack — бинарные для производительности.
- Сериализация/десериализация превращает объект в байты и обратно; в FastAPI это делает Pydantic.
- Безопасность: угрозы перехвата, подмены и отказа в обслуживании; защита — TLS, заголовки безопасности, JWT/OAuth, валидация ввода.
- Оптимизация: кеширование (заголовки, CDN,
304 Not Modified) и сжатие (gzip/Brotli) дают быстрый отклик малой ценой.
Вопросы для самопроверки
- Чем HTTPS отличается от HTTP и какие три гарантии безопасности он обеспечивает?
- Зачем в TLS используется и асимметричное, и симметричное шифрование? Какую роль играет каждое?
- В чём принципиальное отличие WebSocket от модели «запрос — ответ» HTTP? Приведите два примера задач, где он нужен.
- Каким HTTP-кодом сервер подтверждает переход на WebSocket?
- На каких трёх технологиях основан gRPC? Почему его обычно используют между сервисами, а не наружу?
- Перечислите типы данных JSON. Как в JSON принято передавать дату и почему?
- Сравните JSON и XML по читаемости, размеру и применению.
- Что такое сериализация и десериализация? Какой инструмент выполняет их в FastAPI?
- Назовите три основные категории сетевых угроз и способ защиты от каждой.
- Как кеширование и сжатие ускоряют работу приложения? Что означает ответ
304 Not Modified?