HTTP
How the Web Talks
LinkedIn Hook
You open your browser, type a URL, hit Enter. 247 milliseconds later, a webpage loads.
What just happened?
Your browser sent a tiny text message to a server somewhere in the world. The server read it, processed it, and sent back an answer. That's HTTP — and it runs every website on the internet.
But most developers don't know:
- Why POST is NOT the right method for updates
- The real difference between 401 and 403
- How HTTP/2 went from "text" to "binary" and why that matters
- Why HTTP is called "stateless" yet somehow remembers your login
Lesson 5.1 of my Networking Interview Prep series covers all of it — with raw HTTP examples, code snippets, and a cheat sheet you can screenshot.
Read the full lesson → [link]
#HTTP #WebDevelopment #NetworkingFundamentals #InterviewPrep #SoftwareEngineering #BackendDevelopment
What You'll Learn
- The restaurant analogy that makes HTTP instantly understandable
- How the HTTP request/response model works end to end
- Every HTTP method — GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS — and when to use each
- Status codes across all five categories (1xx through 5xx) with the ones that actually appear in interviews
- The most important HTTP headers and what they do
- Why HTTP is stateless and how cookies/sessions patch that gap
- The evolution from HTTP/1.1 to HTTP/2 to HTTP/3 — binary framing, multiplexing, QUIC
- What idempotency means and why it matters for API design
- How to read and write raw HTTP requests and responses
The Restaurant Analogy
Before touching any technical detail, picture a restaurant.
You are the customer (the browser). The waiter is HTTP — the protocol that carries your order to the kitchen and brings back the food. The kitchen is the server — it does the actual work and produces the response.
You do not walk into the kitchen yourself. You do not know how the kitchen is organized. You place an order using a standard format the waiter understands, and you receive food in a standard format back.
That is HTTP in one paragraph.
Each order is independent. The waiter does not remember your previous orders from last week. If you want your usual dish, you have to say it every time. This is what "stateless" means, and we will come back to it.
The Request/Response Model
HTTP is a client-server protocol. Every HTTP interaction follows the same pattern:
- The client opens a TCP connection to the server (port 80 for HTTP, 443 for HTTPS).
- The client sends an HTTP request.
- The server processes it and sends back an HTTP response.
- The connection is closed (or kept alive for reuse in HTTP/1.1+).
Everything on the web — loading a page, submitting a form, fetching JSON from an API — follows this cycle.
A Raw HTTP Request
This is what your browser actually sends over the wire. No magic, just text:
GET /api/users/42 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
Cache-Control: no-cache
Connection: keep-alive
Line by line:
GET— the HTTP method (what action to take)/api/users/42— the path (what resource to act on)HTTP/1.1— the protocol version- Everything below — headers (key-value metadata)
- GET requests have no body; POST/PUT/PATCH requests do
A Raw HTTP Response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 87
Cache-Control: max-age=3600
Set-Cookie: session_id=abc123; HttpOnly; Secure
X-Request-ID: req-7f3a2b1c
{
"id": 42,
"name": "Rakibul Hasan",
"email": "mail.liilab@gmail.com"
}
Line by line:
HTTP/1.1— protocol version200 OK— status line (code + reason phrase)- Headers follow (Content-Type, Cache-Control, etc.)
- A blank line separates headers from the body
- The body is the actual payload (JSON here)
HTTP Methods In Depth
HTTP methods describe the intent of the request. The server decides how to handle them, but there is a widely followed convention.
| Method | Purpose | Idempotent | Has Body |
|---|---|---|---|
| GET | Fetch a resource | Yes | No |
| POST | Create a resource | No | Yes |
| PUT | Replace a resource fully | Yes | Yes |
| PATCH | Update a resource partially | No* | Yes |
| DELETE | Remove a resource | Yes | Optional |
| HEAD | Like GET but no response body | Yes | No |
| OPTIONS | Ask what methods are allowed | Yes | No |
*PATCH can be designed to be idempotent, but it is not required to be by the spec.
GET — Fetch, Never Modify
// GET: retrieve user profile
// Safe to call multiple times — same result every time
fetch("https://api.example.com/users/42", {
method: "GET",
headers: {
"Accept": "application/json",
"Authorization": "Bearer <token>"
}
})
.then(res => res.json())
.then(user => console.log(user));
// No body allowed in GET requests
POST — Create, Not Idempotent
// POST: create a new user
// Calling this twice creates TWO users — not idempotent
fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json", // tells server what format we're sending
"Authorization": "Bearer <token>"
},
body: JSON.stringify({
name: "Rakibul Hasan",
email: "mail.liilab@gmail.com"
})
})
.then(res => {
// Correct response for resource creation is 201 Created
if (res.status === 201) {
return res.json();
}
});
PUT vs PATCH — Full Replace vs Partial Update
// PUT: send the ENTIRE object — fields you omit get cleared/defaulted
// Calling PUT with the same body multiple times = same result (idempotent)
fetch("https://api.example.com/users/42", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: "Rakibul Hasan", // required
email: "mail.liilab@gmail.com", // required
role: "admin" // required — omitting this would remove the role
})
});
// PATCH: send only what changed — other fields are untouched
fetch("https://api.example.com/users/42", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
role: "admin" // only updating the role — name and email stay as-is
})
});
HEAD and OPTIONS
HEAD /api/users/42 HTTP/1.1
Host: api.example.com
HEAD returns headers only — no body. Useful for checking if a resource exists, or getting its Content-Length before downloading.
OPTIONS /api/users HTTP/1.1
Host: api.example.com
Origin: https://myfrontend.com
Access-Control-Request-Method: POST
OPTIONS is the preflight request that browsers send before cross-origin (CORS) requests. The server responds with what methods and origins it allows.
Idempotency — Why It Matters
An operation is idempotent if performing it multiple times produces the same result as doing it once.
Think of a light switch (idempotent): pressing "turn off" five times leaves the light off — same as pressing it once. Now think of an ATM withdrawal (not idempotent): withdrawing $100 five times takes $500.
// Idempotent example: DELETE
// Deleting a user that doesn't exist anymore should return 404 or 204,
// NOT crash — the end state (user is gone) is the same either way
async function deleteUser(id) {
const res = await fetch(`https://api.example.com/users/${id}`, {
method: "DELETE"
});
// 204 No Content — deleted successfully
// 404 Not Found — already gone, which is fine
// Both are acceptable outcomes for an idempotent DELETE
if (res.status === 204 || res.status === 404) {
console.log("User is gone — operation succeeded");
}
}
// Calling deleteUser(42) ten times is safe
// The user ends up deleted regardless — no side effects accumulate
Why does idempotency matter? In distributed systems, networks fail. Clients retry. If your API is idempotent, retries are safe. If it is not (like POST create), retries create duplicates.
HTTP Status Codes
Status codes tell the client what happened. There are five categories.
1xx — Informational
Rarely seen in application code. 100 Continue tells the client to keep sending a large request body.
2xx — Success
| Code | Name | Meaning |
|---|---|---|
| 200 | OK | Standard success — body contains the result |
| 201 | Created | Resource was created — usually after POST |
| 204 | No Content | Success but nothing to return — common for DELETE/PATCH |
3xx — Redirect
| Code | Name | Meaning |
|---|---|---|
| 301 | Moved Permanently | Resource is at a new URL forever — search engines update |
| 302 | Found | Temporary redirect — original URL may come back |
| 304 | Not Modified | Cached version is still fresh — do not re-download |
4xx — Client Error (your fault)
| Code | Name | Meaning |
|---|---|---|
| 400 | Bad Request | Malformed request — invalid JSON, missing required field |
| 401 | Unauthorized | Not authenticated — no token, or token expired |
| 403 | Forbidden | Authenticated but not allowed — you are not an admin |
| 404 | Not Found | Resource does not exist at this path |
| 405 | Method Not Allowed | You used GET on an endpoint that only accepts POST |
| 429 | Too Many Requests | Rate limit hit — slow down |
5xx — Server Error (their fault)
| Code | Name | Meaning |
|---|---|---|
| 500 | Internal Server Error | Generic server crash — something unexpected happened |
| 502 | Bad Gateway | The gateway received an invalid response from an upstream server |
| 503 | Service Unavailable | Server is overloaded or down for maintenance |
| 504 | Gateway Timeout | The upstream server did not respond in time |
Important HTTP Headers
Headers are metadata attached to requests and responses. These are the ones you need to know cold.
Request Headers
| Header | What it does |
|---|---|
Content-Type | Format of the request body (application/json, multipart/form-data) |
Accept | What format the client wants back (application/json, text/html) |
Authorization | Credentials — Bearer <token> for JWT, Basic <base64> for basic |
Cache-Control | Caching instructions (no-cache, no-store, max-age=3600) |
Cookie | Sends stored cookies to the server |
X-Request-ID | Custom ID for tracing a request through distributed systems |
Response Headers
| Header | What it does |
|---|---|
Content-Type | Format of the response body |
Cache-Control | How long the client should cache the response |
Set-Cookie | Instructs the browser to store a cookie (HttpOnly, Secure flags) |
Location | Used with 201/3xx to point to the new/redirect URL |
# Example: server sets a session cookie after login
HTTP/1.1 200 OK
Set-Cookie: session_id=abc123xyz; Path=/; HttpOnly; Secure; SameSite=Strict
Content-Type: application/json
{"message": "Login successful"}
# HttpOnly — JavaScript cannot read this cookie (prevents XSS theft)
# Secure — Only sent over HTTPS
# SameSite — Controls cross-site sending (CSRF protection)
HTTP is Stateless — And Why That's a Problem
HTTP has no memory. Every request stands alone. The server does not know if you made a request one second ago or one year ago. There is no built-in concept of a "session."
The problem: Login requires state. After you log in, the server needs to know who you are on the next request.
The solution: Cookies and session tokens
Flow:
1. POST /login {username, password}
|
v
2. Server validates credentials
Server creates a session in its database
Server returns: Set-Cookie: session_id=abc123
3. Browser stores the cookie automatically
4. GET /dashboard
Cookie: session_id=abc123 ← browser sends it on every request
|
v
5. Server looks up session_id in database
Finds the associated user
Returns the dashboard data for that user
Two common approaches:
Server-side sessions: Session data stored in the database or Redis. The cookie holds only a session ID. Revocation is easy — just delete the session row.
JWT (JSON Web Tokens): The token itself contains the user data (claims), signed by the server. No database lookup needed. Revocation is hard — the token is valid until it expires.
HTTP/1.1 vs HTTP/2 vs HTTP/3
HTTP/1.1 (1997)
- Text-based protocol — requests and responses are human-readable strings
- Persistent connections — one TCP connection can be reused for multiple requests (Connection: keep-alive)
- Head-of-line blocking: requests on a connection are processed in order. If request #1 is slow, requests #2, #3, and #4 wait — even if the server could answer them instantly
- Workaround: browsers open 6 parallel TCP connections per domain (wasteful)
HTTP/1.1 Connection (one at a time, blocking):
Request 1 ----> [slow response]
<---- Response 1
Request 2 ---->
<---- Response 2
Request 3 ---->
<---- Response 3
HTTP/2 (2015)
- Binary framing — requests and responses are broken into binary frames, not text
- Multiplexing — multiple requests travel over ONE TCP connection simultaneously, interleaved as frames. Head-of-line blocking is gone at the HTTP layer
- Header compression (HPACK) — headers are compressed and deduplicated across requests (headers like
HostandAuthorizationdo not repeat in full) - Server Push — server can proactively send resources the client will need (e.g., push CSS and JS before the browser asks)
- Still runs over TCP — TCP-level head-of-line blocking remains
HTTP/2 Connection (all multiplexed on one TCP connection):
Stream 1: Request 1 frame --> ... <-- Response 1 frames
Stream 2: Request 2 frame --> ... <-- Response 2 frames (simultaneous)
Stream 3: Request 3 frame --> ... <-- Response 3 frames (simultaneous)
HTTP/3 (2022)
- Replaces TCP with QUIC (a protocol built on top of UDP)
- Built-in TLS 1.3 encryption — security is part of the protocol, not layered on top
- 0-RTT handshake — for returning clients, the connection can be established with zero round trips (QUIC merges the transport and crypto handshakes)
- True multiplexing — QUIC handles streams independently at the transport layer, so packet loss on one stream does not block others (solves TCP's head-of-line blocking)
- Connection migration — if you switch from WiFi to mobile data, the QUIC connection survives (identified by a connection ID, not IP/port)
Handshake comparison for HTTPS:
HTTP/1.1 + TLS 1.2:
TCP SYN, SYN-ACK, ACK (1 RTT)
TLS ClientHello ... (2 RTT)
First request (3 RTT)
HTTP/2 + TLS 1.3:
TCP + TLS combined (1 RTT)
First request (2 RTT)
HTTP/3 + QUIC:
QUIC + TLS 1.3 combined (1 RTT, or 0 RTT for returning clients)
First request (1 RTT or 0 RTT)
Common Mistakes
-
Using POST for updates instead of PUT or PATCH. POST is for creation. Using it for updates violates REST conventions, breaks idempotency (retries create duplicates), and confuses other developers. Use PUT for full replacement, PATCH for partial updates.
-
Confusing 401 Unauthorized with 403 Forbidden. Despite its name, 401 means "not authenticated" — the server does not know who you are (missing or invalid credentials). 403 means "authenticated but not authorized" — the server knows who you are, but you do not have permission. A logged-in user hitting an admin endpoint gets 403, not 401.
-
Assuming HTTP/2 requires HTTPS. The HTTP/2 specification (RFC 7540) does not mandate TLS. However, every major browser only implements HTTP/2 over TLS (h2), and no browser supports HTTP/2 in cleartext (h2c). In practice, HTTP/2 without HTTPS does not work in any browser — but technically the spec allows it.
Interview Questions
Q: What is the difference between PUT and PATCH?
PUT replaces the entire resource. If you send a PUT with a partial object, the fields you omit are removed or reset to defaults. PATCH applies a partial update — only the fields you include are changed, and the rest stay as they are. Both methods target a specific resource URL (e.g., /users/42). PUT is required by the spec to be idempotent; PATCH is not, though it can be designed that way. Use PUT when you have the full representation of the resource; use PATCH when you only want to change specific fields.
Q: What does idempotent mean and which HTTP methods are idempotent?
An operation is idempotent if calling it multiple times produces the same result as calling it once. The end state of the system is identical regardless of how many times you apply the operation. Idempotent HTTP methods: GET, HEAD, PUT, DELETE, OPTIONS. Non-idempotent: POST (creates a new resource each time), and PATCH by default (though it can be made idempotent). Idempotency matters for safety in distributed systems — if a network failure causes a client to retry a request, idempotent operations are safe to retry without side effects.
Q: What is the difference between 401 and 403?
401 Unauthorized means the request lacks valid authentication credentials. The client is not identified — the token is missing, expired, or invalid. The solution is to log in or refresh the token. Despite its name "Unauthorized," it really means "unauthenticated."
403 Forbidden means the client is authenticated (the server knows who you are) but does not have permission to access the resource. You are logged in as a regular user trying to hit an admin endpoint. No amount of re-authenticating will fix a 403 — you need higher privileges.
Memory trick: 401 = "Who are you?", 403 = "I know who you are, but no."
Q: How does HTTP/2 solve the head-of-line blocking problem of HTTP/1.1?
In HTTP/1.1, requests on a single connection are processed sequentially — if request #1 takes 500ms, requests #2 and #3 wait even if they could be answered in 5ms. The workaround was opening 6 parallel TCP connections per domain, which is wasteful.
HTTP/2 introduces binary framing and multiplexing. Requests and responses are broken into small binary frames, each tagged with a stream ID. Multiple streams (independent request/response pairs) are interleaved over a single TCP connection. The server can respond to requests #2 and #3 before finishing #1, and the client reassembles responses by stream ID. This eliminates HTTP-layer head-of-line blocking. Note: TCP-level head-of-line blocking still exists in HTTP/2, which HTTP/3 (QUIC over UDP) solves completely.
Q: Why is HTTP stateless and how do sessions work?
HTTP is stateless because each request is completely independent. The server has no built-in memory of previous requests — it processes every request in isolation. This was a deliberate design choice that makes HTTP servers simple, scalable, and cacheable.
The problem is that real applications need state (login sessions, shopping carts, preferences). The solution is to store state somewhere and send a reference with each request.
Sessions work like this: when a user logs in, the server creates a session record (in a database or Redis), generates a unique session ID, and sends it to the browser via Set-Cookie. The browser stores the cookie and sends it back automatically on every subsequent request via the Cookie header. The server reads the session ID, looks up the session, and knows who the user is — simulating statefulness on top of a stateless protocol. JWTs work similarly but encode the state in the token itself rather than a server-side store.
Quick Reference — Cheat Sheet
HTTP Methods
| Method | Purpose | Idempotent | Has Body | Success Code |
|---|---|---|---|---|
| GET | Fetch resource | Yes | No | 200 |
| POST | Create resource | No | Yes | 201 |
| PUT | Replace resource (full) | Yes | Yes | 200 / 204 |
| PATCH | Update resource (partial) | No* | Yes | 200 / 204 |
| DELETE | Remove resource | Yes | Optional | 204 |
| HEAD | Fetch headers only | Yes | No | 200 |
| OPTIONS | Query allowed methods/CORS | Yes | No | 200 / 204 |
*PATCH can be designed to be idempotent, but the spec does not require it.
HTTP Status Codes by Category
| Range | Category | Key Codes |
|---|---|---|
| 1xx | Informational | 100 Continue |
| 2xx | Success | 200 OK, 201 Created, 204 No Content |
| 3xx | Redirect | 301 Moved Permanently, 302 Found, 304 Not Modified |
| 4xx | Client Error | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 405 Method Not Allowed, 429 Too Many Requests |
| 5xx | Server Error | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout |
HTTP Version Comparison
| Feature | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Protocol format | Text | Binary frames | Binary (QUIC) |
| Transport | TCP | TCP | UDP (QUIC) |
| Multiplexing | No (workaround) | Yes | Yes (true) |
| Header compression | No | Yes (HPACK) | Yes (QPACK) |
| TLS | Optional | Required in browsers | Built-in (always) |
| Head-of-line blocking | HTTP level | TCP level only | None |
| 0-RTT connection | No | No | Yes (returning) |
Raw HTTP at a Glance
REQUEST RESPONSE
------- --------
METHOD /path HTTP/version HTTP/version STATUS_CODE Reason
Header: value Header: value
Header: value Header: value
(blank line)
(blank line) Body (JSON, HTML, etc.)
Body (for POST/PUT/PATCH)
Previous: Lesson 4.4 — Ports & Sockets (
../ch04-tcp-udp/04-ports-and-sockets.md) Next: Lesson 5.2 — HTTPS (02-https.md)
This is Lesson 5.1 of the Networking Interview Prep Course — 8 chapters, 32 lessons.