Урок: Мережевий фундамент — від проводу до Python¶
Перш ніж вивчати Django, потрібно зрозуміти, де живе твій код. Django — це лише один шар у великому стеку. Цей документ описує всі шари нижче.
Навіщо це вивчати?¶
Коли ти пишеш python manage.py runserver і відкриваєш браузер — відбуваються десятки операцій: DNS-запит, TCP-з'єднання, HTTP-переговори, парсинг запиту. Більшість розробників не знають, що відбувається до того, як запит досягає їхнього Python-коду. Це і є причина більшості помилок у продакшні.
1. Що таке мережа?¶
Мережа — це система, де два або більше комп'ютери можуть обмінюватися даними. Фізично це дроти, оптоволокно, Wi-Fi сигнал. Логічно — це набір протоколів (домовленостей про мову).
Рівні абстракції (OSI-модель — спрощено)¶
| Рівень | Що робить | Приклад |
|---|---|---|
| Фізичний | Передає біти | Кабель, Wi-Fi |
| Канальний | Адресує в локальній мережі | MAC-адреса |
| Мережевий | Маршрутизація між мережами | IP |
| Транспортний | Надійна передача | TCP, UDP |
| Прикладний | Протоколи для програм | HTTP, DNS, SSH |
Ключова ідея: Кожен рівень вирішує одну задачу і не знає деталей інших рівнів.
2. IP-адреса — де живе комп'ютер¶
IP-адреса (Internet Protocol Address) — унікальний числовий ідентифікатор кожного пристрою в мережі.
IPv4¶
Чотири числа (0–255), розділені крапками. Всього ~4 мільярди адрес. Майже вичерпано.
IPv6¶
128-бітна адреса. Практично необмежений простір.
Публічна vs Приватна IP¶
| Тип | Приклад | Видима з Інтернету |
|---|---|---|
| Публічна | 104.21.14.55 |
Так |
| Приватна | 192.168.1.x, 10.0.0.x |
Ні (тільки в локальній мережі) |
Коли ти відкриваєш localhost:8000 — ти звертаєшся до 127.0.0.1, адреси самого себе (loopback).
3. DNS — телефонна книга Інтернету¶
Комп'ютери спілкуються через IP-адреси. Але люди запам'ятовують google.com, а не 142.250.74.46.
DNS (Domain Name System) — розподілена система, яка перекладає домени в IP-адреси.
Як відбувається DNS-резолюція¶
- Ти вводиш
github.comу браузер - Браузер перевіряє локальний кеш (чи не знає вже цю адресу)
- Якщо немає — запитує DNS Resolver (зазвичай від інтернет-провайдера або
8.8.8.8) - Resolver запитує Root DNS Server (знає лише TLD-сервери)
- Root сервер вказує на TLD сервер (для
.com— Verisign) - TLD сервер вказує на Authoritative DNS (де зберігаються реальні записи
github.com) - Authoritative DNS повертає IP:
140.82.121.4 - Браузер кешує відповідь і з'єднується з сервером
DNS-записи¶
| Тип | Що робить | Приклад |
|---|---|---|
A |
Домен → IPv4 | github.com → 140.82.121.4 |
AAAA |
Домен → IPv6 | |
CNAME |
Аліас на інший домен | www.example.com → example.com |
MX |
Де email-сервер | |
TXT |
Довільний текст (SPF, верифікація) |
Реальний бекенд: При деплої Django-проєкту ти купуєш домен і додаєш
A-запис, що вказує на IP твоєї хмарної VM.
Чому браузер завантажується швидше вдруге? — DNS-відповідь кешується на час TTL (Time To Live). Повторний запит іде прямо з кешу.
4. Порти — квартири в будинку¶
IP-адреса доставляє пакет до потрібного комп'ютера. Але на одному комп'ютері може бути десятки програм. Порт вказує, до якої саме програми надходить трафік.
192.168.1.100:80 ← веб-сервер (Nginx)
192.168.1.100:5432 ← PostgreSQL
192.168.1.100:22 ← SSH
192.168.1.100:8000 ← Django runserver
Відомі порти¶
| Порт | Протокол | Використання |
|---|---|---|
| 80 | HTTP | Веб (без шифрування) |
| 443 | HTTPS | Веб (з TLS) |
| 22 | SSH | Безпечний доступ до сервера |
| 5432 | PostgreSQL | База даних |
| 6379 | Redis | Кеш / брокер |
| 25 | SMTP | |
| 53 | DNS | DNS-запити |
Реальний бекенд: Якщо ти запускаєш два Django-проєкти одночасно на порту 8000 — другий виведе
Address already in use. ОС не може прив'язати один порт до двох процесів.
5. TCP — надійна доставка¶
TCP (Transmission Control Protocol) забезпечує гарантовану та впорядковану доставку даних.
Як це працює¶
Дані розбиваються на пакети (chunks). Кожен пакет: - має порядковий номер - може йти різними маршрутами через Інтернет - може прийти не в тому порядку
TCP на стороні отримувача: - перевіряє порядкові номери - запитує повторну відправку втрачених пакетів - збирає пакети у правильному порядку
TCP Three-Way Handshake¶
Перш ніж відправити будь-які дані, TCP встановлює з'єднання:
Клієнт → Сервер: SYN (Привіт, можемо поговорити?)
Сервер → Клієнт: SYN-ACK (Так, я готовий)
Клієнт → Сервер: ACK (Чудово, починаємо)
[З'єднання встановлено]
Клієнт → Сервер: HTTP GET / (Тепер надсилаємо дані)
Аналогія: Уяви, що відправляєш 300-сторінкову книгу по пошті посторінково. Поштова служба (IP) може відправити сторінки різними шляхами. Друг (TCP) дивиться на номери сторінок, збирає книгу по порядку і просить надіслати повторно сторінку 47, якщо вона загубилася.
UDP — швидка, ненадійна альтернатива¶
UDP (User Datagram Protocol) надсилає пакети без підтвердження. Використовується там, де втрата пакету краща за затримку: відеозв'язок, онлайн-ігри, DNS.
6. HTTP — мова вебу¶
HTTP (HyperText Transfer Protocol) — текстовий протокол прикладного рівня. Описує формат запитів і відповідей між браузером і сервером.
Структура HTTP-запиту¶
GET /api/users/42/ HTTP/1.1
Host: example.com
Accept: application/json
Authorization: Bearer eyJhbGc...
Content-Type: application/json
{"name": "Alice"}
| Частина | Що це |
|---|---|
GET |
Метод (дія) |
/api/users/42/ |
Шлях (ресурс) |
HTTP/1.1 |
Версія протоколу |
Host, Accept... |
Заголовки (метадані) |
{"name": "Alice"} |
Тіло (тільки для POST/PUT/PATCH) |
HTTP-методи¶
| Метод | Призначення | Ідемпотентний |
|---|---|---|
GET |
Отримати ресурс | Так |
POST |
Створити ресурс | Ні |
PUT |
Повністю замінити | Так |
PATCH |
Частково оновити | Ні |
DELETE |
Видалити | Так |
Структура HTTP-відповіді¶
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 48
Set-Cookie: sessionid=abc123; HttpOnly
{"id": 42, "name": "Alice", "email": "alice@mail.com"}
Коди статусу¶
| Діапазон | Значення | Приклади |
|---|---|---|
| 2xx | Успіх | 200 OK, 201 Created, 204 No Content |
| 3xx | Редирект | 301 Moved Permanently, 302 Found |
| 4xx | Помилка клієнта | 400 Bad Request, 401 Unauthorized, 404 Not Found |
| 5xx | Помилка сервера | 500 Internal Server Error, 503 Service Unavailable |
7. HTTPS та TLS¶
HTTPS = HTTP + TLS (Transport Layer Security). TLS шифрує дані між клієнтом і сервером.
Навіщо це потрібно?¶
Без HTTPS будь-який вузол між клієнтом і сервером (маршрутизатор у кав'ярні, провайдер) може прочитати твій запит — включно з паролями та токенами.
TLS Handshake (спрощено)¶
- Клієнт: "Я підтримую TLS 1.3, ось мій рандомний ключ"
- Сервер: "Ок, ось мій SSL-сертифікат і публічний ключ"
- Клієнт: "Перевірив сертифікат (підписаний довіреним CA). Генерую session key."
- Обидві сторони: "Тепер шифруємо все сесійним ключем"
SSL-сертифікат видається довіреними організаціями (Certificate Authorities): Let's Encrypt, DigiCert тощо. Nginx зберігає сертифікат і виконує TLS-handshake до того, як запит дійде до Python.
8. Sockets — фундамент мережевого програмування¶
Socket — це двонаправлена точка з'єднання між двома програмами. Це низькорівневий API, який надає операційна система.
Як Python відкриває мережеве з'єднання (низький рівень)¶
import socket
# Сервер
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 8080)) # Прив'язуємо до порту
server.listen(5) # Чекаємо підключень
conn, addr = server.accept() # Блокує, поки клієнт не підключиться
data = conn.recv(1024) # Читаємо дані
conn.send(b"HTTP/1.1 200 OK\r\n\r\nHello")
conn.close()
# Клієнт
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
client.send(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")
response = client.recv(4096)
Django, Flask, FastAPI — всі вони зрештою використовують саме цей механізм, просто з великою кількістю абстракцій зверху.
Unix Domain Sockets¶
У продакшні Nginx і uWSGI часто спілкуються через Unix socket (файл у файловій системі, напр. /run/django.sock) замість мережевого. Це швидше, бо не проходить через мережевий стек.
9. Stateless протокол та стан сесій¶
HTTP за своєю природою stateless — без пам'яті. Кожен запит повністю незалежний. Сервер не пам'ятає, що ти вже робив запит секунду тому.
Як тоді сайт знає, що ти залогінений?¶
Через cookies і sessions:
Схема:
1. Ти відправляєш POST /login/ з логіном/паролем
2. Сервер перевіряє дані, створює session в базі даних з унікальним ID
3. Сервер відправляє відповідь із заголовком Set-Cookie: sessionid=abc123
4. Браузер зберігає cookie і автоматично додає його до кожного наступного запиту: Cookie: sessionid=abc123
5. Сервер читає sessionid, знаходить сесію в БД і знає, хто ти
Cookie-атрибути¶
| Атрибут | Що робить |
|---|---|
HttpOnly |
JavaScript не може читати (захист від XSS) |
Secure |
Надсилається тільки через HTTPS |
SameSite |
Захист від CSRF |
Expires |
Коли cookie стає недійсним |
10. Client/Server архітектура¶
У класичній архітектурі є дві ролі:
| Роль | Хто | Що робить |
|---|---|---|
| Client | Браузер, мобільний додаток | Ініціює запит, відображає результат |
| Server | Nginx, Django, PostgreSQL | Пасивно чекає, обробляє, відповідає |
Повний lifecycle запиту (від URL до HTML)¶
1. Користувач вводить https://shop.example.com/products/
2. DNS: shop.example.com → 203.0.113.10
3. TCP Handshake з сервером 203.0.113.10:443
4. TLS Handshake (шифрування)
5. HTTP GET /products/ відправлено
6. Nginx отримує запит
7. Nginx пересилає до uWSGI через Unix socket
8. uWSGI перетворює HTTP в Python dict (WSGI environ)
9. Django URL Dispatcher: /products/ → ProductListView
10. Middleware: SecurityMiddleware → SessionMiddleware → AuthMiddleware
11. View: Product.objects.all() → SQL SELECT → Python objects
12. Template: рендеринг HTML з даними
13. HttpResponse 200 OK з HTML
14. Nginx відправляє відповідь клієнту
15. Браузер парсить HTML, завантажує CSS/JS
11. REST API архітектура¶
REST (Representational State Transfer) — архітектурний стиль для проектування API.
Принципи REST¶
| Принцип | Пояснення |
|---|---|
| Stateless | Кожен запит містить усю потрібну інформацію |
| Resource-based | URL описує ресурс (/users/, /products/42/) |
| HTTP Verbs | Дія виражена методом (GET, POST, PUT, DELETE) |
| Uniform Interface | Стандартна поведінка для всіх ресурсів |
REST URL-конвенції¶
GET /api/products/ → список всіх продуктів
POST /api/products/ → створити продукт
GET /api/products/42/ → отримати продукт #42
PUT /api/products/42/ → повністю оновити продукт #42
PATCH /api/products/42/ → частково оновити продукт #42
DELETE /api/products/42/ → видалити продукт #42
12. Як бекенд отримує запит — під капотом¶
Що відбувається на рівні ОС коли приходить HTTP-запит:
1. NIC (мережева карта) отримує електричний сигнал → перетворює в байти
2. ОС: TCP/IP stack обробляє пакети → збирає HTTP-запит
3. ОС: дивиться, яка програма слухає порт 80 → це Nginx
4. ОС: копіює дані в буфер Nginx через системний виклик recv()
5. Nginx: парсить HTTP-заголовки
6. Nginx: дивиться на location rules у nginx.conf
7. Nginx: proxy_pass → відправляє до unix:/run/django.sock
8. uWSGI: читає з сокету → парсить HTTP → будує WSGI environ dict
9. uWSGI: викликає Django application(environ, start_response)
10. Django: решта — це Python
Ключовий інсайт: Весь шлях — це серія перетворень байтів між різними програмами через буфери ОС. Python-код — це останній рядок у ланцюжку.
Типові помилки — мережевий рівень¶
1. Блокуючі запити в синхронному коді¶
# ПОГАНО: блокує весь процес на час HTTP-запиту
import requests
def my_view(request):
response = requests.get("https://slow-api.example.com/data") # чекає 5 сек
return JsonResponse(response.json())
# ДОБРЕ: async view (Django 3.1+)
import httpx
async def my_view(request):
async with httpx.AsyncClient() as client:
response = await client.get("https://slow-api.example.com/data")
return JsonResponse(response.json())
2. Неправильне розуміння stateless¶
Не зберігай стан у глобальних змінних Python — при кількох workers кожен має свою пам'ять. Стан повинен бути в БД або Redis.
3. Відсутність HTTPS¶
Ніколи не деплой продакшн без TLS. Пам'ятки, паролі, токени — все йде відкритим текстом.
Питання для самоперевірки¶
- Що відбувається, якщо DNS-сервер недоступний? Чи дійде запит до сайту?
- Навіщо потрібен TCP handshake, якщо можна просто надіслати дані одразу?
- Чому
127.0.0.1іlocalhost— це одне і те ж? - Як сервер дізнається, що ти залогінений, якщо HTTP stateless?
- Чому
python manage.py runserverне підходить для продакшну?