HTTP/HTTPS β Part 1: Foundations of How the Web Communicates
What is this?
Imagine you could only talk to a vast library by mailing in postcards. Each postcard has a strict, agreed-upon shape: the first line says exactly what you want ("send me the book on page 42"), a few lines of fine print spell out details ("I read English; I'll accept a photocopy"), and then you drop it in the mailbox. The library mails back its own postcard: a one-line verdict ("here it is" / "no such page" / "you're not allowed"), some fine print of its own, and then the goods. The library never writes to you out of the blue β it only ever replies. And it has no memory: every postcard you send must re-state who you are and what you want, because the library forgot you the instant it sealed the last reply.
That postcard format β the rigid grammar that every browser, phone app, server, and microservice on Earth has agreed to speak β is HTTP. It's the lingua franca of the web. When you open a page, tap a button, or call an API, what actually crosses the wire is a stack of these postcards.
The one-line idea: HTTP is a strict request/response message format that every web client and server agrees on β the client always asks first, the server always answers once, and neither remembers the conversation afterward.
That last clause β neither remembers β looks like a bug and is actually the secret to scaling the entire web. We'll keep coming back to the postcard, and you'll see why "forgetful" is a feature, not a flaw. Across these four parts we'll build it up properly: the message anatomy and methods (Part 2), the TLS encryption and the HTTP/2-vs-3 performance saga (Part 3), and how all of it shows up in interviews (Part 4).
1. What HTTP actually is
HTTP stands for HyperText Transfer Protocol. Strip away the jargon and it's three promises baked into how clients and servers talk:
- It's requestβresponse. One side asks, the other answers. Exactly one response per request β no more, no less.
- The client always speaks first. A server, in plain HTTP, can never knock on your door unprompted. It waits to be asked. (This single rule is why "the server wants to push me a notification" gets hard β and why we invented polling, long-polling, Server-Sent Events, and WebSockets to work around it. More on that in Part 4.)
- It's stateless. Each request stands completely alone. The server doesn't remember your last one.
The clients are browsers, mobile apps, and backend services calling each other. The servers are web servers, API servers, and microservices. HTTP is the one grammar they all share, which is exactly why a Python service can call a Go service that calls a Rust service and nobody has to negotiate a custom dialect.
π‘ "Client always initiates" sounds like trivia, but it shapes huge swaths of architecture. Real-time chat, live stock tickers, multiplayer games β every one of them is a workaround for the fact that HTTP servers can't speak first.
2. What HTTPS adds
HTTPS is not a different protocol. It's the exact same HTTP postcards β but sealed inside a tamper-proof, opaque envelope before they ever leave your hands.
HTTPS = HTTP + TLS
TLS (Transport Layer Security) wraps the connection and buys you three things:
- π Confidentiality β nobody on the wire (your cafΓ©'s Wi-Fi, your ISP, a router in between) can read your traffic.
- β Integrity β nobody can alter it in flight without the tampering being detected.
- π Authentication β you can be sure the server is actually
bank.comand not an impostor, because it proves its identity with a certificate.
Today HTTPS is effectively mandatory. Browsers slap a "Not Secure" warning on plain HTTP, search engines rank it lower, and features like HTTP/2 require it in practice. We'll crack open the TLS handshake in Part 3 β for now, just hold the image: HTTP is the postcard; HTTPS is the same postcard inside a sealed, signed envelope.
3. Why a protocol like this won
Before HTTP, getting two arbitrary machines to exchange data meant inventing a bespoke protocol every time. HTTP won the web because it picked a few unglamorous-but-decisive traits:
- Text-based and human-readable. You can literally read a raw HTTP request with your eyes β which makes debugging, logging, and learning enormously easier.
- Universally understood semantics.
GETmeans read,404means not found β everywhere, for everyone. - Extensible through headers. Need a new capability? Add a header. The core never had to change to support cookies, compression, caching, or auth β those all rode in as headers.
- Stateless, therefore scalable. Because no request depends on server memory, you can throw any request at any server. (Section 5.)
Here's a real request β this is genuinely what travels over the wire:
GET /products HTTP/1.1
Host: api.maang.io
User-Agent: Mozilla/5.0
Accept: application/json
Three plain lines of text: what you want (GET /products), which host (you can run many sites on one IP, so the server needs to be told), and a little fine print about who's asking and what they'll accept. That readability is a feature you'll be grateful for the first time you curl -v a misbehaving endpoint.
4. The evolution: HTTP/0.9 β HTTP/3
HTTP didn't arrive fully formed. Each version solved the pain of the last, and the why behind each jump is exactly what interviewers probe β so let's walk the timeline as a story.
- HTTP/0.9 (1991) β comically bare. One method (
GET), no headers, no status codes. You asked for a document, you got raw HTML, the connection closed. That was the whole protocol. - HTTP/1.0 (1996) β the version that made HTTP useful. It added headers (metadata β content types, caching hints), status codes (so a server could say "not found" instead of just hanging up), and support for non-HTML content. But it opened a fresh TCP connection per request and slammed it shut after β wildly wasteful.
- HTTP/1.1 (1997, refined 2014) β the workhorse that ran the web for two decades. Its headline fix was persistent connections (
Connection: keep-alive): reuse one TCP connection for many requests instead of paying the handshake tax every time. It also added the Host header (so one server can host many domains β the foundation of shared hosting and the modern cloud) and chunked transfer encoding (stream a response whose length you don't know yet). - HTTP/2 (2015) β same semantics (still
GET, still headers, still200 OK), radically different delivery. It switched from text to a compact binary framing layer, introduced multiplexing (many requests in flight on one connection at once), and HPACK header compression. This killed application-layer head-of-line blocking. - HTTP/3 (2022) β the deepest change: it ditched TCP entirely and runs over QUIC, a protocol built on UDP. This finally kills transport-layer head-of-line blocking and makes connections survive a network switch (Wi-Fi β cellular) without dropping.
We'll dissect HTTP/1.1 vs /2 vs /3 β and the two different kinds of head-of-line blocking they each fix β in glorious detail in Part 3. The thread tying every version together: the meaning of an HTTP message never changed; only how efficiently it gets delivered did.
5. HTTP is stateless β the foundation everything rests on
Back to the forgetful library. Send two requests:
Request 1: GET /cart
Request 2: POST /checkout
The server treats these as two strangers who've never met. It has no built-in idea that the same person who looked at the cart is now checking out. Statelessness means the server keeps no memory of past requests β every request must carry everything needed to understand it.
So how does a shopping cart work at all? You re-introduce yourself on every postcard, by attaching an identity token the server can look up:
- cookies (a session ID the browser re-sends automatically)
- JWTs (a signed token that contains your identity)
- session IDs stored in a shared store like Redis
We'll cover the mechanics of cookies and sessions in Part 2. The point here is why the web's designers chose forgetfulness on purpose. It looks like a handicap; it's actually the superpower:
Because no request depends on a particular server's memory, any server can handle any request. And that one fact unlocks:
- Horizontal scaling β need more capacity? Launch another identical server. No coordination required.
- Load balancing with no session affinity β the load balancer can fling requests at whichever server is least busy, because they're interchangeable. (This is exactly the "stateless backends" win from the load-balancer chapter β HTTP's statelessness is why that pattern works.)
- Resilience β a server dying mid-traffic doesn't destroy anyone's session, because the session lives in the shared store, not in that server's RAM.
The trade-off, honestly stated: identity now lives outside the server (in Redis, a database, or a self-contained JWT), and you re-validate it on every request. That's a small tax for near-infinite elasticity β and we'll weigh it properly in Part 4.
6. How a single request actually flows
Here's the whole transaction in its simplest form β one postcard out, one postcard back:
Four traits to lock in, because they define HTTP's entire personality:
- The client initiates β the server is purely reactive.
- Exactly one response comes back per request.
- It's stateless β this exchange knows nothing of any other.
- It's text-based (at least through HTTP/1.1) β readable, debuggable, loggable.
7. The URL: the address on the postcard
Every request is aimed at a URL (Uniform Resource Locator) β the precise address of the thing you want.
https://api.maang.io/v1/users?limit=20
Break it into its parts, because each one drives real architectural decisions:
| Part | What it is | Why it matters |
|---|---|---|
https:// |
scheme/protocol | encrypted (HTTPS) vs not (HTTP) |
api.maang.io |
host/domain | DNS resolves it; the load balancer routes on it |
/v1/users |
path | how you version APIs and route to services |
?limit=20 |
query string | filters, pagination β and part of the cache key |
These aren't cosmetic. A load balancer routes by host and path (the Layer 7 routing from the load-balancer chapter). A CDN caches by the full URL including the query string β so ?limit=20 and ?limit=50 are two different cache entries. Get your URL design right and caching, routing, and versioning all fall into place.
8. Status codes: the server's one-line verdict
Every response leads with a three-digit status code β the server's verdict on what happened. The first digit tells you the whole story; memorize the five classes and you can read any response at a glance.
The four you'll meet daily:
- 2xx β Success.
200 OK(here's your data),201 Created(your POST made a new resource),204 No Content(success, but nothing to return). - 3xx β Redirection.
301 Moved Permanently(this resource lives at a new URL forever β browsers and search engines cache this),302 Found(temporary detour β don't cache the move),304 Not Modified(your cached copy is still fresh β a caching workhorse from Part 3). - 4xx β Client error. You messed up.
400 Bad Request,401 Unauthorized(you're not logged in),403 Forbidden(you're logged in but not allowed),404 Not Found,429 Too Many Requests(rate-limited). - 5xx β Server error. The server messed up.
500 Internal Server Error,502 Bad Gateway(a proxy got a bad answer from upstream),503 Service Unavailable(overloaded or down for maintenance).
β οΈ The 4xx-vs-5xx line is one engineers blur constantly, and it matters: a
4xxsays "don't retry the same request, it'll fail again β fix your input." A5xxsays "the request was fine; the server hiccupped β retrying might work." Your retry logic, your alerting, and your load balancer's behavior all hinge on getting this distinction right.
9. Idempotency β the interview favorite
This word comes up in every API design interview, so let's nail it. A method is idempotent if making the same call once or a hundred times leaves the server in the same final state.
| Method | Idempotent? | Safe? | Why |
|---|---|---|---|
GET |
β Yes | β Yes | reads only, changes nothing |
PUT |
β Yes | β No | replaces the resource with X β doing it twice still lands on X |
DELETE |
β Yes | β No | delete once or five times β the thing is gone either way |
POST |
β No | β No | each call creates something new β call it 3Γ and you get 3 orders |
Two distinct ideas hide here, and seniors keep them separate:
- Safe = read-only, no side effects at all (
GET,HEAD). - Idempotent = repeating it doesn't compound the effect (
GET,PUT,DELETEβ and every safe method).
Why does anyone care? Retries. Networks drop. A request times out β did the server get it or not? You have no idea. If the call is idempotent, you just retry, no harm done. If it's not (a POST that charges a credit card), a blind retry might double-charge the customer. This is the reason load balancers will auto-retry a failed GET but never a POST, and the reason real-world POST endpoints add an idempotency key to make themselves safely retryable. We'll go deep on this in Part 4 β it's a near-guaranteed question.
10. Why HTTPS exists, in one image
Back to our postcard. A plain HTTP request is exactly that β a postcard. Anyone who handles it along the way β the cafΓ© Wi-Fi, your ISP, any router in between β can read every word, and worse, scribble on it before passing it along.
HTTPS is the same message inside a sealed, tamper-evident, signed envelope. Only you and the real server can open it; any tampering shows; and the signature proves the server is who it claims to be.
That little dance up front is the TLS handshake: agree on a shared secret, verify the server's certificate, and from then on every HTTP postcard travels inside an encrypted tunnel. It costs a round trip or two at connection setup β which is precisely why connection reuse (keep-alive, session resumption) matters so much. We'll take this handshake apart frame by frame in Part 3.
Key takeaways
- HTTP is a strict, text-based, request/response format that every web client and server agrees on β the client always asks first, the server answers exactly once, and it's the lingua franca that lets any service talk to any other.
- HTTPS is the same HTTP, sealed in a TLS envelope β adding confidentiality, integrity, and server authentication. It's effectively mandatory today.
- Statelessness is the load-bearing design choice: the server forgets every request, which is why any server can handle any request β unlocking horizontal scaling, affinity-free load balancing, and resilience.
- Status codes and idempotency are the two literacy tests: read the first digit (2/3/4/5) to know what happened, and know which methods are safe to retry (
GET/PUT/DELETE) versus dangerous (POST). - The protocol's meaning has stayed constant from HTTP/1.1 to /3 β only the efficiency of delivery changed, which is the whole story of Part 3.
Next up, Part 2 opens the postcard itself: the exact anatomy of a request and response, what each method and header does, how cookies smuggle state past a stateless protocol, and how keep-alive and CORS shape the connection.