Foundations

HTTP, TCP/IP, DNS, TLS — jak vlastně teče request.

Než napíšeš jediný řádek backendu, musíš rozumět tomu, co se vlastně stane, když někdo otevře tvůj web. Zadáš adresu, zmáčkneš Enter — a za zlomek vteřiny se načte stránka. Mezitím proběhne několik kroků na několika různých technologiích. Tahle kapitola je projde všechny, pomalu a od nuly. Je to úplný základ: odkazuje se na něj každá další kapitola, tak ho neproskakuj.


Pár pojmů na úvod (ať se neztratíš)

Backend je program, který běží na nějakém počítači připojeném k internetu (tomu počítači se říká server) a odpovídá na požadavky. Ten, kdo se ptá — prohlížeč, mobilní aplikace — je klient.

  • Request (požadavek) = zpráva od klienta serveru: „pošli mi domovskou stránku", „ulož tuhle objednávku".
  • Response (odpověď) = zpráva, kterou server pošle zpátky: stránka, data, nebo hlášení o chybě.
  • Protokol = dohodnutá pravidla, jak spolu klient a server mluví, aby si rozuměli (např. HTTP).
  • IP adresa = číselná adresa počítače v síti, podobně jako adresa domu. Třeba 104.21.5.7.
  • Port = číslo „dveří" na tom počítači. Na jedné IP může běžet víc služeb a každá poslouchá na svém portu (web má výchozí porty 80 pro HTTP a 443 pro HTTPS — proto je v URL nevidíš; ale je to jen konvence, lokální dev běží třeba na 3000 nebo 8080).

Celý backend ve své podstatě dělá jen tohle: přišel request → něco s ním udělej → vrať response. Pořád dokola, klidně milionkrát za den. Všechno ostatní v téhle učebnici je jen rozpracování téhle jedné věty.


Co se stane, když zadáš adresu (mentální model)

Když do prohlížeče napíšeš adresu a dáš Enter, proběhnou zhruba tyhle kroky, než vůbec uvidíš stránku:

Nelekej se pojmů v diagramu — projdeme je teď jeden po druhém v tomhle pořadí: DNS → TCP → TLS → HTTP. Až to dočteš, vrať se sem a diagram ti dá smysl celý. (Reverse proxy, CDN a load balancer si vysvětlíme níže a hlavně v dalších kapitolách — zatím ber, že je to „pár serverů, které stojí před tvojí aplikací".)


1. DNS — překlad jména na adresu

Lidi si pamatují jména (google.com), ale počítače se v síti hledají podle IP adres. DNS (Domain Name System) je telefonní seznam internetu: dáš mu jméno a vrátí ti IP adresu.

Takže úplně první věc, kterou prohlížeč udělá, není stažení stránky — je to dotaz: „jakou IP adresu má google.com?" Teprve když zná IP, ví, kam se vůbec připojit.

  • Odpovědi se cachují (dočasně ukládají) na spoustě míst — v prohlížeči, v operačním systému, u tvého poskytovatele internetu — aby se nemusel stejný překlad dělat znovu a znovu.
  • TTL (Time To Live) říká, jak dlouho se smí odpověď cachovat, než si ji musí vyžádat znovu. Krátké TTL = změny se projeví rychle, ale je víc dotazů. Dlouhé TTL = míň dotazů, ale změna se „rozjíždí" pomaleji.
  • Kdo se koho ptá: tvůj počítač se ptá rekurzivního resolveru (u poskytovatele / veřejného jako 1.1.1.1), a ten teprve obejde hierarchii root → TLD (.cz) → autoritativní server domény. Cache je hlavně na tom resolveru — proto změnu na registrátorovi „nevidíš" hned.
  • Typický zmatek začátečníka: přesměruješ doménu jinam a „nefunguje to" — přitom se ti jen ještě chvíli servíruje stará IP z cache. Není to bug, je to TTL. A pozor — cachují se i negativní odpovědi (NXDOMAIN), takže „přidal jsem záznam a chvíli to nešlo" je taky normální. (Příkaz dig example.com v terminálu ti ukáže, jakou IP doména právě vrací.)

Pro úplnost, druhy DNS záznamů (zatím stačí vědět, že existují): A = IPv4 adresa, AAAA = IPv6 adresa, CNAME = „tahle doména je přezdívka jiné", MX = kam doručovat e-maily, TXT = textová poznámka (často pro ověření vlastnictví domény).


2. TCP — navázání spolehlivého spojení

Teď, když prohlížeč zná IP, musí se k serveru připojit. Data se po internetu posílají v malých kouscích zvaných pakety — představ si dlouhý dopis rozstříhaný na pohlednice, které putují každá zvlášť a můžou dorazit v jiném pořadí (nebo se cestou ztratit).

  • IP se stará jen o doručení paketů z bodu A do bodu B — bez záruky, že dorazí všechny a ve správném pořadí.
  • TCP je vrstva nad IP, která tu nespolehlivost schová: pakety seřadí, ztracené pošle znovu a zařídí, aby na druhé straně vyšel kompletní, správně poskládaný proud dat. Proto se mu říká spolehlivý protokol.

Než si spolu dva začnou „povídat", musí se nejdřív pozdravit — tomu se říká handshake:

Klient:  „Slyšíš mě?"        (SYN)
Server:  „Jo, a ty mě?"      (SYN-ACK)
Klient:  „Jo, jedeme."       (ACK)

Tenhle pozdrav stojí jeden round-trip (cesta tam a zpět), a to je čas. Proto se navázaná spojení snaží znovupoužívat místo otevírání nového na každý request. Tahle drobnost je zdrojem překvapivě velké části výkonových problémů — třeba otevírat nové spojení do databáze na každý požadavek je „malá" chyba s velkým dopadem (víc v kapitole Concurrency a Performance & Scaling).

UDP je bratříček TCP, který tyhle záruky nemá — pakety prostě vystřelí a nestará se, jestli dorazily. Zní to špatně, ale pro video hovory, hry nebo právě DNS je to výhra: radši rychle a občas ztratit paket než čekat na potvrzení. Klíčová myšlenka: vědět, kdy obětovat spolehlivost za rychlost.


3. TLS / HTTPS — zašifrování a ověření

To „s" v https znamená secure. Bez něj by si kdokoli na cestě mezi tebou a serverem (Wi-Fi v kavárně, tvůj poskytovatel) mohl přečíst i změnit, co posíláš. TLS to řeší dvěma věcmi naráz:

  1. Šifrování — data putují jako v zalepené obálce, kterou po cestě nikdo nepřečte.
  2. Ověření identity — server se prokáže certifikátem, takže máš jistotu, že mluvíš se skutečným mojebanka.cz, a ne s podvrženým serverem útočníka. Certifikátu věříš proto, že ho podepsala důvěryhodná autorita (CA), které věří už tvůj prohlížeč.

Tohle ověření je další handshake a stojí další round-tripy (novější TLS 1.3 to zkrátil). Je to další důvod, proč je drahé navazovat spojení pořád znovu.

Časté problémy, na které narazíš: expirovaný certifikát (platnost mají omezenou, musí se obnovovat) nebo špatně nakonfigurovaný řetěz certifikátů — prohlížeč pak ukáže to varování o „nedůvěryhodném připojení".


4. HTTP — vlastní jazyk requestů

Konečně se dostáváme k samotné konverzaci. HTTP je protokol, kterým si klient a server řeknou, co chtějí. Každý request má:

  • metodu (co chci dělat — viz níže),
  • cestu (/courses/42 — který zdroj),
  • hlavičky (headers — doplňující informace, např. v jakém formátu chci data),
  • volitelně tělo (body — data, která posílám, třeba obsah nové objednávky).

A každá responsestatus kód (jak to dopadlo), hlavičky a tělo (data nebo HTML).

„Stateless" — server tě po každém requestu zapomene

HTTP je stateless (bezstavový): server si mezi jednotlivými requesty nic nepamatuje. Každý request musí přijít se vším kontextem, který server potřebuje — hlavně „kdo jsem". Proto s každým požadavkem posíláš znovu cookie nebo token — je to jako ukazovat lístek pokaždé, když projdeš turniketem, protože tě obsluha mezi průchody nepozná.

Zní to jako nevýhoda, ale je to obrovská výhoda: když si server nedrží žádný osobní stav, může tvůj request obsloužit kterýkoli ze serverů — a to je přesně to, co umožňuje přidávat servery a škálovat (víc o tom v Performance & Scaling).

Metody — co chci s daty dělat

MetodaCo znamenáBezpečná (jen čte)?Idempotentní?
GETpřečti zdroj
POSTvytvoř / proveď akci
PUTnahraď celý zdroj
PATCHuprav část zdrojezáleží
DELETEsmaž zdroj

U PATCH „záleží" znamená podle toho, co děláš: PATCH {stav: "zaplaceno"} (nastavení na pevnou hodnotu) je idempotentní, ale PATCH {pocet: pocet + 1} (přičtení) idempotentní není.

Idempotentní je slovo, které uvidíš v téhle učebnici pořád, tak hned na začátku jednoduše: operace je idempotentní, když ji provedeš dvakrát a výsledek je stejný jako jednou. Smazat objednávku #5 dvakrát = pořád je smazaná (idempotentní). Ale poslat „zaplať 500 Kč" dvakrát = dvě platby (NEidempotentní!). Proto se u plateb řeší speciálně — viz Patterny.

Status kódy — jak to dopadlo

Server v každé odpovědi vrací třímístné číslo. Stačí znát skupiny:

  • 2xx = povedlo se. 200 OK, 201 vytvořeno, 204 OK ale bez dat.
  • 3xx = přesměrování. 301 trvale jinam, 302 dočasně jinam, 304 „nezměnilo se, použij cache". (Past: po 301/302 může prohlížeč změnit POST na GET; 307/308 původní metodu zachovají.)
  • 4xx = chyba na straně klienta (request je špatně). 400 špatný request, 401 nepřihlášen, 403 přihlášen, ale nemá právo, 404 neexistuje, 409 konflikt, 422 neprošla validace, 429 moc requestů (rate limit).
  • 5xx = chyba na straně serveru (server to pokazil). 500 interní chyba, 502/503/504 problémy s nedostupností nebo timeoutem (odpověď nepřišla včas — viz dole u TCP).

Nejčastější záměna: 401 vs 403. 401 = „nevím, kdo jsi" (přihlas se). 403 = „vím, kdo jsi, ale na tohle nemáš právo". Plést si je je klasická juniorská chyba.

Hlavičky, které potkáš

Hlavičky jsou doplňkové info ke každému requestu/response. Pár, které uvidíš pořád: Content-Type (v jakém formátu jsou data, např. JSON), Authorization (token, kterým se prokazuješ), Cache-Control (jak dlouho se smí odpověď cachovat — viz Caching).

Verze HTTP (jen ať víš, že existují)

HTTP/1.1 je stará klasika. HTTP/2 umí poslat víc požadavků přes jedno spojení naráz (multiplexing). Jenže běží nad TCP, kde ztráta jednoho paketu pozdrží všechny streamy (TCP head-of-line blocking) — a přesně to řeší HTTP/3 tím, že běží nad UDP (QUIC). To je celý důvod jeho existence. Jako junior nemusíš řešit detaily, ale tahle pointa „proč HTTP/3" stojí za zapamatování.


Cookies a sessions — jak si tě server „pamatuje"

Řekli jsme, že HTTP je stateless a server tě po každém requestu zapomene. Jak tedy zůstaneš přihlášený? Přes cookie — malý kousek dat, který server pošle prohlížeči, a ten ho pak automaticky přikládá ke každému dalšímu requestu na ten web. Funguje to dvěma způsoby:

  • Session cookie — v cookie je jen náhodné ID session, podle kterého si server v paměti/databázi najde, kdo jsi. Stav je na serveru. (Pozor: to ID je samo o sobě tajemství — kdo ho ukradne, je přihlášený za tebe, tomu se říká session hijacking. Proto HttpOnly níže.)
  • Token v cookie — v cookie je rovnou token, který nese informaci o tobě (detaily v Security).

U cookies si pak hlídáš tři bezpečnostní nastavení (víc v Security): HttpOnly (cookie nepřečte JavaScript → ochrana před krádeží), Secure (posílá se jen po HTTPS) a SameSite (omezí, kdy se cookie přikládá → ochrana před CSRF).


Cachování a komprese — ať se nepřenáší zbytečně

Dvě hlavičky, kterými server šetří přenos (víc v Caching):

  • Cache-Control říká prohlížeči (a CDN), jak dlouho si smí odpověď schovat, aby ji nestahoval pořád dokola.
  • ETag + If-None-Match je „otisk" verze obsahu. Prohlížeč při dalším dotazu pošle otisk, který má; když se nezměnil, server odpoví krátkým 304 Not Modified místo posílání celých dat znovu.

A komprese (gzip/brotli): server odpověď před odesláním zmenší a prohlížeč ji rozbalí — menší data putují sítí rychleji. Většinou to zapne server sám.


CORS — proč ti volání projde v terminálu, ale ne v prohlížeči

Tohle tě dřív nebo později „kousne", tak ať víš dopředu. CORS je bezpečnostní pravidlo prohlížeče (ne tvého serveru!). Prohlížeč z principu nedovolí, aby JavaScript na webu A.cz volal server na B.cz, pokud to server B.cz výslovně nepovolí speciální hlavičkou.

Důsledek, který mate každého: úplně stejný požadavek projde z terminálu (příkazem curl), ale v prohlížeči spadne na CORS chybu. Není to bug v tvém kódu — curl totiž žádné takové bezpečnostní pravidlo nemá, kdežto prohlížeč ano. Řešení je doplnit na serveru správné CORS hlavičky.


Failure modes — jak to v praxi „praská"

Tyhle tři chyby vypadají podobně, ale každá znamená něco jiného. Umět je rozlišit = umět rychle najít příčinu:

  • Connection refused — na druhé straně nikdo neposlouchá (služba neběží, nebo voláš špatný port).
  • Timeout — spojení se navázalo, ale odpověď nepřišla včas (server je přetížený, nebo na něčem zaseknutý).
  • Connection reset — spojení bylo násilně přerušeno (něco po cestě ho zabilo, server spadl).

A jedna past, na kterou tě připraví zbytek učebnice: slepě opakovat (retry) neidempotentní POST po timeoutu může vést k duplicitní akci — třeba dvě platby. Proto se requesty a opakování musí navrhovat s rozmyslem (viz Patterny → Idempotency).


🛠️ Cvičení

Pár cvičení používá nástroje, které možná vidíš poprvé (DevTools v prohlížeči, curl, dig v terminálu). To je záměr — nejlíp se to naučíš tím, že si na ně sáhneš.

  1. Sleduj reálný request. V prohlížeči otevři vývojářské nástroje (F12) → záložka Network, načti libovolný web a najdi: status kód, hlavičku Content-Type a (v záložce Timing) jak dlouho trval TLS handshake.
  2. Zkus dig a curl. V terminálu spusť dig example.com (uvidíš IP adresu) a curl -v https://example.com (uvidíš handshake i hlavičky requestu a response). Najdi v outputu status kód.
  3. Vyrob si CORS chybu. Na libovolném webu otevři konzoli (F12 → Console) a napiš fetch('https://example.org'). Přečti chybovou hlášku a vysvětli, proč by stejné volání přes curl prošlo.
  4. Zařaď status kódy. Ke každé situaci přiřaď kód: nepřihlášený uživatel, přihlášený bez práv, neexistující stránka, neprošla validace formuláře, spadl server, příliš mnoho requestů.
  5. Idempotence v praxi. U každého rozhodni, jestli je bezpečné poslat to dvakrát, a proč: GET /orders/5, DELETE /orders/5, POST /orders, PUT /orders/5.
Náčrt řešení — rozbal, až si cvičení zkusíš sám
  1. Sleduj reálný request — v Network panelu klikni na konkrétní request, status najdeš v záhlaví, Content-Type v Response headers a TLS čas v záložce Timing („SSL"). Pozor: TLS čas uvidíš jen u prvního spojení — další requesty ho znovupoužijí (proto je 0), tak hledej ten první, na který se navazuje.
  2. Zkus dig a curldig ti vypíše A záznam (IP), curl -v ukáže celý handshake i hlavičky; status kód je první řádek odpovědi (HTTP/2 200). Na co pozor: řádky začínající * jsou diagnostika spojení (DNS/TCP/TLS), > je tvůj request, < je response — neplést si je.
  3. Vyrob si CORS chybufetch spadne, protože example.org nepošle hlavičku Access-Control-Allow-Origin, takže prohlížeč odpověď zablokuje. Klíčová pointa: blokuje prohlížeč, ne server — curl žádné CORS pravidlo nemá, proto stejné volání projde. Nejde o chybu v kódu, ale o chybějící povolení na serveru.
  4. Zařaď status kódy — nepřihlášený 401, přihlášený bez práv 403, neexistující stránka 404, neprošlá validace 422, spadlý server 500, příliš requestů 429. Klasická past: nepřihlášenému vracet 403 místo 401 (401 = „nevím kdo jsi", 403 = „vím, ale nesmíš").
  5. Idempotence v praxiGET, PUT i DELETE jdou opakovat bez vzniku duplicit (jsou idempotentní), POST /orders ne (každé volání vytvoří novou objednávku). Pozor: nepleť „idempotentní" se „safe" — safe je jen metoda, co vůbec nemění stav (GET); PUT/DELETE stav mění, jen opakování nepřidá nic navíc. DELETE je idempotentní co do stavu (po prvním je smazáno), i když druhé volání může vrátit 404 — to nevadí.

🧠 Otázky & odpovědi

Proč volání projde v curlu, ale v prohlížeči spadne na CORS?

CORS je bezpečnostní pravidlo prohlížeče, ne vlastnost serveru. Prohlížeč zakáže JavaScriptu volat jiný web, dokud to ten web výslovně nepovolí hlavičkou (Access-Control-Allow-Origin). curl v terminálu žádné takové pravidlo nemá, takže prostě pošle požadavek. Proto „v curlu to jede, v appce ne" — a proto to není chyba v tvém kódu, ale chybějící povolení na serveru.

Jaký je rozdíl mezi 401 a 403?

401 Unauthorized = „nevím, kdo jsi" — chybí nebo je neplatné přihlášení, takže se přihlas. 403 Forbidden = „vím, kdo jsi, ale na tohle nemáš právo" — jsi přihlášený, ale nemáš oprávnění. Častá chyba je vracet 403 tam, kde je uživatel jen nepřihlášený.

Co znamená, že je HTTP stateless, a proč je to výhoda?

Server si mezi requesty nic nepamatuje — každý požadavek musí přinést všechen kontext sám (kdo jsem → cookie/token). Výhoda: protože si žádný server nedrží „tvůj" stav, může tě obsloužit kterýkoli z nich. Stav se ukládá mimo (do databáze nebo cache), takže když přidáš další servery, hned zvládneš víc uživatelů. To je základ horizontálního škálování.

Proč je drahé otevírat nové spojení a co s tím?

Navázat spojení znamená udělat TCP handshake a (u HTTPS) i TLS handshake — to jsou cesty tam a zpět, tedy čas, plus alokace zdrojů. Když otevíráš nové spojení na každý požadavek (třeba do databáze), platíš tu cenu pokaždé a navíc můžeš vyčerpat limit spojení. Řešení je spojení znovupoužívat (connection pooling — drží se sada otevřených spojení a recyklují se).

Rozliš connection refused, timeout a connection reset.

Refused = na druhé straně nikdo neposlouchá (služba neběží nebo voláš špatný port). Timeout = spojení se navázalo, ale odpověď nepřišla včas (přetížení, zaseknutí). Reset = spojení bylo násilně přerušeno (něco po cestě ho ukončilo, server spadl). Každé ukazuje na jinou příčinu, takže je neházej do jednoho pytle — rozlišení ti ušetří hodiny debugování.

Když je HTTP stateless, jak zůstanu přihlášený?

Přes cookie — malý kousek dat, který server pošle prohlížeči a ten ho automaticky přikládá ke každému dalšímu requestu na ten web. V cookie bývá buď ID session (server si podle něj najde, kdo jsi), nebo rovnou token nesoucí informaci o tobě. Server tě tak při každém requestu „pozná", aniž by si mezi nimi cokoli pamatoval.

Co je ETag a co znamená 304 Not Modified?

ETag je „otisk" verze obsahu, který server pošle s odpovědí. Při dalším dotazu prohlížeč ten otisk přiloží zpátky; když se obsah nezměnil, server místo posílání celých dat odpoví krátkým 304 Not Modified = „nic nového, použij, co máš v cache". Šetří to přenos i čas — nestahuje se znovu něco, co se nezměnilo.