1.1
Client–Server Architecture and the Request–Response Cycle
Who asks, who answers, and exactly what travels in an HTTP request and response.
30 min Reading + animations
Tip: tap or hover any dotted-underlined term to see what it means.
By the end of this lesson you will be able to
- Explain the client–server model: who starts a conversation, who holds the data, and why it is called centralised.
- Walk through the request–response cycle in five phases, from a click to a rendered page.
- Take a URL apart (scheme, host, port, path, query, fragment) and say who uses each part.
- Read a raw HTTP request and response: request line, status line, headers, blank line, body.
- Choose the right method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS) and say which are safe and which are idempotent.
- Interpret status codes from 1xx to 5xx, including the ones interviewers love: 201, 204, 304, 401 vs 403, 409, 429, 502, 503, 504.
- Explain keep-alive, HTTP/1.1 vs HTTP/2 vs HTTP/3, and how a client should handle timeouts and retries without doing anything twice.
#What client–server means
Client–server architecture is the foundation of web networking. It is a centralised model in which the work is split into two roles:
- Client: the side that asks for a service or data. Examples: your web browser, a mobile app, Postman, the
curlcommand. - Server: the side that holds the data, the logic and the resources in one central place, and answers clients’ requests. Examples: Nginx, Apache, a Node.js/Express app, a Spring Boot server. What a server really is (machine, program, port) is the next lesson; how Nginx, Apache and app servers work inside is in Web Servers and App Servers.
+-----------------+ +-----------------+
| | ──── 1. HTTP Request ──► | |
| Client | | Server |
| (Browser/App) | ◄─── 2. HTTP Response ── | (Node/Nginx/…) |
+-----------------+ +-----------------+
The client always speaks first. The server waits, listening on a known address and port (443 for HTTPS), and only ever replies. Clients talk to each other through the server, never directly, and only the server touches the database.
Client and server: who talks to whom
Clients start every conversation. The server sits in one central place and owns the data and the logic.
Scenario
You click a link. The browser is the client: it is the side that asks. A server never contacts a browser out of the blue in plain HTTP.
Why build it this way?
- One source of truth. Data and business rules live in one place, so every client (web, Android, iOS) sees the same thing.
- Control and security. The server checks every request before acting on it. A client is any program on someone else’s device and can never be trusted.
- Thin clients. Phones and browsers do not need the whole database or all the logic.
The price is that the server is a bottleneck and a single point of failure (SPOF): if it is slow or down, every client suffers. Real systems therefore run many copies of the server behind a load balancer, which brings its own problems (the next lesson).
#The request–response cycle
Every exchange between client and server follows the same cycle, the HTTP request–response cycle:
1. Request creation
The user does something (enters a URL, clicks a button) and the client builds an HTTP request. It contains:
- HTTP method: what the client wants to do (GET = fetch data, POST = send new data, PUT = update, DELETE = remove).
- URL / endpoint: the exact destination on the server, for example
https://api.example.com/users. - Headers: extra metadata about the request, for example
Content-Type: application/jsonorAuthorization: Bearer <token>. - Body (payload): the actual data sent with POST, PUT or PATCH, such as form data or JSON.
2. Network transmission
The request travels over TCP/IP through routers and ISPs to the server’s IP address and port (443 for HTTPS, 80 for plain HTTP). Before the first byte of HTTP, the client must find the IP (DNS, lesson 1.8) and open a connection (TCP and TLS, lesson 1.9), unless it can reuse one.
3. Server processing
The server’s router (the code kind, not the network box) looks at the method and path and calls the matching handler. The handler checks who is asking, validates the input, runs the business logic, and reads or writes the database if needed.
4. Response generation
The server builds an HTTP response:
- Status code: the outcome (200 OK = success, 201 Created = a new resource was made, 400 Bad Request = the client made a mistake, 401 Unauthorized = authentication needed, 404 Not Found = no such resource, 500 Internal Server Error = the server failed).
- Headers: metadata from the server, such as
Content-Type: text/htmlorapplication/json, orSet-Cookie. - Body: the actual content: an HTML page, JSON data, an image…
5. Rendering or consumption
The response returns to the client. A browser renders it and shows it to the user; a mobile app processes the data and updates its screens. A page usually needs more: after reading the HTML, the browser sends further requests for CSS, JavaScript, images and fonts, each its own request–response cycle.
The request–response cycle
Five phases: create the request, send it, process it, build the response, render it.
Scenario
A user action (typing a URL, clicking a link or a button) starts every cycle.
#Anatomy of a URL
A URL (Uniform Resource Locator) tells the client which protocol to speak, which machine to contact, on which port, and which resource to ask for.
https://shop.example.com:443/products/42?color=red&size=m#reviews
└─┬─┘ └──────┬───────┘ └┬┘└────┬────┘ └──────┬───────┘ └──┬──┘
scheme host port path query fragment
| Part | Example | Who uses it, and how |
|---|---|---|
| Scheme | https | The client: speak HTTP inside TLS. http means unencrypted |
| Host | shop.example.com | DNS turns it into an IP; it is also sent in the Host header, because one IP can serve many sites |
| Port | 443 | Usually left out: 443 is the default for https, 80 for http. Written only when different, e.g. localhost:3000 |
| Path | /products/42 | The server’s router: which resource (here product 42) |
| Query | ?color=red&size=m | The handler: key=value pairs joined by &, for filters, search, pagination |
| Fragment | #reviews | Only the browser: it is never sent to the server; the page scrolls to that element |
Anatomy of a URL: who uses each part
A URL is a set of instructions. Each part is used by a different player.
Scenario
https://shop.example.com/products/42?color=red&size=m#reviews
Scheme
https
Host
shop.example.com
Port
443 (implied)
Path
/products/42
Query
?color=red&size=m
Fragment
#reviews
The whole URL (Uniform Resource Locator) answers four questions: which protocol, which machine, which port, which resource.
#Inside an HTTP message
HTTP (Hypertext Transfer Protocol) is the language clients and servers use for web requests and responses. HTTPS (HTTP Secure) is the same HTTP carried inside an encrypted TLS connection, so nobody on the path can read or change it.
In HTTP/1.1 a message is plain text with a fixed shape: a first line, headers, a blank line, then an optional body.
Inside an HTTP request and response
Every HTTP/1.1 message has the same shape: a first line, headers, a blank line, then an optional body.
Scenario
First a connection exists: a TCP connection from your port 51544 to the server’s port 443, wrapped in TLS for HTTPS. HTTP text travels inside it.
A real request, as it travels in HTTP/1.1:
POST /api/orders HTTP/1.1
Host: shop.example.com
User-Agent: Mozilla/5.0 (…) Chrome/130
Accept: application/json
Content-Type: application/json
Content-Length: 31
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0MiJ9.k3…
{"productId": 42, "quantity": 2}
And the server’s reply:
HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 52
Location: /api/orders/981
Cache-Control: no-store
{"id": 981, "productId": 42, "quantity": 2, "paid": false}
The very simplest request a browser makes when you open Google looks like this (simplified):
GET / HTTP/2
Host: www.google.com
HTTP/2 200
content-type: text/html
#HTTP methods
The method says what the client wants to do with the resource named by the URL.
| Method | Meaning | Body? | Safe | Idempotent | Typical success |
|---|---|---|---|---|---|
| GET | Fetch a resource | No | ✅ | ✅ | 200 OK |
| HEAD | Same as GET, but headers only | No | ✅ | ✅ | 200 OK |
| OPTIONS | Which methods/origins are allowed here? (CORS preflight) | No | ✅ | ✅ | 204 No Content |
| POST | Send data to be processed; usually create a new resource | Yes | ❌ | ❌ | 201 Created |
| PUT | Replace the resource at this URL with this full version (or create it there) | Yes | ❌ | ✅ | 200 / 204 |
| PATCH | Change only some fields | Yes | ❌ | not guaranteed | 200 / 204 |
| DELETE | Remove the resource | Rarely | ❌ | ✅ | 204 No Content |
Two words in that table matter enormously in system design:
- Safe: the request does not change anything on the server. Browsers can prefetch it, crawlers can follow it, caches can store the answer.
- Idempotent: doing it once or ten times leaves the server in the same state. That makes it safe to retry after a timeout. Note that the response may differ: a second DELETE returns 404, but the resource is gone either way.
HTTP methods and what they do to data
Watch the badge under the database: it shows the stored resource after each request.
Scenario
Read. Safe and idempotent.
The database holds user 42.
There are two rarer methods you may see in references: CONNECT (asks a proxy to open a tunnel, used for HTTPS through proxies) and TRACE (echoes the request back for debugging, normally disabled for security).
Self-checkQuestion
A mobile app times out while sending a request and wants to retry automatically. Which request is safe to retry as-is?
#Status codes
Every response starts with a three-digit status code. The first digit is the class:
| Class | Meaning | Who should act |
|---|---|---|
| 1xx Informational | “Got it, carry on” | Rare in daily work |
| 2xx Success | It worked | Nobody |
| 3xx Redirection | Look elsewhere (or use your cached copy) | The client follows automatically |
| 4xx Client error | The request was wrong | The client must change something |
| 5xx Server error | The server failed | The server team; the client may retry later |
The codes you must know:
| Code | Name | When you see it |
|---|---|---|
| 100 | Continue | Server agrees to receive a large body the client asked about (Expect: 100-continue) |
| 101 | Switching Protocols | Answer to a WebSocket upgrade |
| 200 | OK | Success, with a body |
| 201 | Created | A new resource was created; Location header says where |
| 202 | Accepted | Queued; will be processed later |
| 204 | No Content | Success, empty body (common for DELETE, PUT) |
| 301 | Moved Permanently | Resource moved for good; browsers remember it (http → https, old URLs) |
| 302 / 307 | Found / Temporary Redirect | Temporarily elsewhere (e.g. to /login); 307 keeps the method |
| 308 | Permanent Redirect | Like 301 but keeps the method and body |
| 304 | Not Modified | Your cached copy is still valid; no body sent |
| 400 | Bad Request | Malformed or invalid input |
| 401 | Unauthorized | Really “unauthenticated”: who are you? Log in |
| 403 | Forbidden | I know who you are; you are not allowed |
| 404 | Not Found | No resource at this URL (also used to hide things you may not see) |
| 405 | Method Not Allowed | E.g. DELETE on an endpoint that only allows GET |
| 409 | Conflict | Clashes with current state: duplicate, or edited by someone else |
| 413 | Content Too Large | Body exceeds the server’s limit |
| 422 | Unprocessable Content | Well-formed but fails validation (some APIs prefer it to 400) |
| 429 | Too Many Requests | Rate limited; check Retry-After |
| 500 | Internal Server Error | Unhandled bug or exception on the server |
| 502 | Bad Gateway | A proxy/load balancer got no valid answer from the server behind it |
| 503 | Service Unavailable | Overloaded or in maintenance; temporary, often with Retry-After |
| 504 | Gateway Timeout | A proxy waited too long for the server behind it |
Status codes: what the server is telling you
The first digit is the class: 1xx info, 2xx success, 3xx go elsewhere, 4xx your fault, 5xx our fault.
Scenario
Most traffic first hits a proxy or load balancer, which forwards it to an app server.
#Headers you will meet every day
Headers are Name: value lines (names are case-insensitive). The important ones:
| Header | Sent by | Purpose |
|---|---|---|
Host | Client | Which site on this IP (mandatory in HTTP/1.1) |
User-Agent | Client | Which browser/app is asking |
Accept | Client | Formats the client can handle, e.g. application/json |
Content-Type | Both | Format of the body, e.g. application/json, text/html; charset=utf-8 |
Content-Length | Both | Body size in bytes, so the receiver knows where the message ends |
Authorization | Client | Credentials, e.g. Bearer <token> |
Cookie | Client | Cookies the browser stored for this site |
Set-Cookie | Server | Ask the browser to store a cookie |
Cache-Control | Both | Caching rules, e.g. max-age=60, no-store |
ETag / If-None-Match | Server / Client | A version tag, and the conditional request that gets a 304 if nothing changed |
Location | Server | Where to go (redirects), or the URL of a newly created resource (201) |
Retry-After | Server | How long to wait before retrying (429, 503) |
You can also invent your own (X-Request-Id for tracing, Idempotency-Key for safe retries). The next lesson is about two of these, Set-Cookie and Cookie, and why they exist at all.
#Connections and HTTP versions
HTTP needs a connection underneath, and opening one is expensive: a TCP handshake costs one round trip, and TLS adds one more (TLS 1.3). The history of HTTP is mostly the story of reusing connections better.
| Version | Year | Transport | What changed |
|---|---|---|---|
| HTTP/1.0 | 1996 | TCP | One request per connection, then close |
| HTTP/1.1 | 1997 | TCP | Keep-alive by default: many requests on one connection, but one at a time; Host header mandatory |
| HTTP/2 | 2015 | TCP + TLS | Binary frames, multiplexing many requests at once on one connection, header compression |
| HTTP/3 | 2022 | QUIC over UDP | Same ideas as HTTP/2, but a lost packet only delays its own stream; faster setup; survives network changes |
How requests share a connection
Opening a connection costs round trips. Each HTTP version found a better way to reuse it.
Scenario
A TCP handshake opens the connection…
- Keep-alive (persistent connections) avoids a new handshake per request. Servers close idle connections after a timeout to save memory.
- Head-of-line blocking: in HTTP/1.1 a slow response holds up the ones behind it, so browsers open about six connections per host. HTTP/2 fixes this at the HTTP level, but one lost TCP packet still stalls all streams; HTTP/3 fixes that too by using QUIC.
- Clients and servers negotiate the version: HTTP/2 during the TLS handshake (ALPN), HTTP/3 when the server advertises it with an
Alt-Svcheader. Everything else (methods, status codes, headers) is the same in all versions.
#When things go wrong on the client side
A client must assume the network will fail. The common cases:
| Failure | What the client sees | What to do |
|---|---|---|
| DNS fails | Name not resolved | Show an error; maybe retry later |
| Server down / port closed | Connection refused (fast) or connect timeout (slow) | Retry with backoff; try another server |
| Request or response lost | Read timeout: silence | Retry only if idempotent or protected by an idempotency key |
| 4xx | An answer saying the request is wrong | Do not retry blindly; fix the input. For 401, get a new token and retry once |
| 429 / 503 | “Slow down / try later” | Wait (Retry-After, or exponential backoff with jitter) |
| 500 / 502 / 504 | Server-side failure | Retry a few times if safe, then show an error |
When the answer does not come: timeouts and retries
Networks lose messages. A good client sets a timeout, retries the right things, and never pays twice.
Scenario
The request is lost on a weak mobile signal.
The key insight: when a request times out, the client cannot know whether the server never received it or processed it and the answer got lost. That is why:
- Always set timeouts (a connect timeout and a read timeout). The default in many libraries is “wait forever”.
- Retry only idempotent requests automatically (GET, PUT, DELETE, HEAD).
- Make important non-idempotent requests idempotent with an idempotency key: the client sends a unique ID with the request, and the server remembers the result for that ID and replays it instead of doing the work twice.
- Use exponential backoff with jitter (wait 1 s, 2 s, 4 s… plus randomness) and a maximum number of attempts, so a struggling server is not crushed by a retry storm.
#Client–server in system design
- Most of the internet is client–server. Websites, REST APIs, mobile backends, and the services inside a company calling each other (where one service is the client of another).
- APIs are the contract. Methods, URLs, status codes and headers form the interface between client and server teams. Using them correctly (201 for creation, 409 for conflicts, idempotent PUT) lets proxies, caches and client libraries behave correctly without special code.
- Scaling the server side means many identical servers behind a load balancer. That works smoothly only if any server can answer any request, which is why HTTP being stateless matters so much: next lesson.
- Caching uses the same protocol:
Cache-Control,ETagand 304 let browsers and CDNs answer requests without reaching your server at all. - Failure handling is part of the design: timeouts, retries, idempotency keys and backoff on the client; 503 with
Retry-Afterand rate limits (429) on the server.
#Try it yourself
curl is a command-line HTTP client available on Windows, macOS and Linux.
# See the whole conversation: request headers (>) and response headers (<)
curl -v https://example.com/
# HEAD request: headers only
curl -I https://example.com/
# Follow redirects (-L) and print only the final status code
curl -s -o /dev/null -w "%{http_code}\n" -L http://github.com/
# POST JSON to a test API that echoes back what it received
curl -X POST https://httpbin.org/post \
-H "Content-Type: application/json" \
-d '{"productId": 42, "quantity": 2}'
# Ask for a status code on purpose
curl -i https://httpbin.org/status/404
# Force HTTP/2 or HTTP/3 (if your curl supports it)
curl -sI --http2 https://www.google.com/ | head -1
On Windows PowerShell, use curl.exe instead of curl (the bare name is an alias for a different command). In a browser, open developer tools (F12), go to the Network tab and reload a page: every row is one request–response cycle, with its method, status, headers, size, protocol (h2, h3) and timing.
#Summary
Key takeaways
- In client–server architecture the client asks and the server answers; the server holds the data and logic centrally, and only it talks to the database. It is simple and controllable, but the server is a bottleneck and a single point of failure.
- The request–response cycle: create the request (method, URL, headers, body) → transmit over TCP/IP → server routes, validates, runs logic → builds a response (status, headers, body) → client renders it. One page usually means many cycles.
- A URL is scheme + host + port + path + query + fragment; the fragment never reaches the server, and secrets never belong in the URL.
- Methods: GET/HEAD/OPTIONS are safe; GET, HEAD, OPTIONS, PUT and DELETE are idempotent; POST is neither, PATCH is not guaranteed. Idempotent means safe to retry.
- Status codes: 2xx success, 3xx redirect or cached (301, 302, 304), 4xx client error (400, 401 unauthenticated, 403 forbidden, 404, 409, 429), 5xx server error (500 code bug, 502/504 from the proxy, 503 temporary).
- Connections: HTTP/1.1 keep-alive reuses a connection one request at a time; HTTP/2 multiplexes; HTTP/3 uses QUIC so packet loss only delays one stream.
- Clients must handle failure: timeouts always, retries with backoff and jitter, and idempotency keys for anything that must not happen twice.
Answer on your own first, then read the explanation, even when you got it right.
Self-checkQuestion
In the client–server model, who starts a conversation?
Self-checkQuestion
In an HTTP/1.1 message, what separates the headers from the body?
Self-checkQuestion
A POST /api/orders succeeds with 201 Created. Which response header tells the client the URL of the new order?
Self-checkQuestion
What does HTTP/3 run on?
Self-checkQuestion
On the server, what decides which piece of code handles GET /products/42?
Self-checkQuestion
Before a cross-origin request, the browser asks the server which methods and origins are allowed. Which method does it use?
Self-checkQuestion
Which part of https://shop.example.com/products/42?color=red#reviews is never sent to the server?
Self-checkQuestion
Which method is neither safe nor idempotent?
Self-checkQuestion
Which two methods are safe, meaning they do not change anything on the server? (Choose two.)
Choose 2
Self-checkQuestion
A user is logged in as a normal customer and opens /admin. What should the server return?
Self-checkQuestion
Your users see 504 Gateway Timeout. Where do you look first?
Self-checkQuestion
A mobile app’s token expired, and its next request gets 401 Unauthorized. What is the right reaction?
Self-checkQuestion
A payment request (POST /payments) times out. The client cannot tell whether the server charged the card. What lets it retry without risking a double charge?
Self-checkQuestion
DELETE /users/42 returns 204. The client retries and now gets 404. Is DELETE still idempotent?
Self-checkQuestion
User 42 has a name, an email and a phone number. A client sends PUT /users/42 with a body that holds only a new email. If the server follows PUT’s meaning, what is stored afterwards?
Self-checkQuestion
A client retries with exponential backoff: it waits 1 s after the first failure, then 2 s, then 4 s, doubling each time. Ignoring jitter and the time each request takes, how long after the first failure does the fifth attempt start?
Self-checkQuestion
A round trip takes 100 ms. Opening an HTTPS connection costs one round trip for TCP and one for TLS 1.3. A page needs 3 requests to the same server. How much connection-setup time does HTTP/1.1 keep-alive save compared with HTTP/1.0 (new connection per request)?
Self-checkQuestion
A load balancer has no healthy app servers left behind it. Which status are users most likely to see?
Self-checkQuestion
An API answers 429 Too Many Requests with Retry-After: 30. What should a well-behaved client do?
Self-checkQuestion
A phone on a lossy mobile network uses HTTP/2. One TCP packet is lost. What happens to the other streams on that connection?
Self-checkQuestion
shop.example.com and blog.example.com are hosted on the same IP address and port. How does the server know which site a request is for?
Self-checkQuestion
A developer builds login as GET /login?user=ana&password=… and says it is fine because the site uses HTTPS. What is the real problem?
Self-checkQuestion
The notes say ‘500 = server crash’. Which statement is the correct version?
Self-checkQuestion
A client gets ‘connection refused’ instantly, before any HTTP is exchanged. What is the most likely cause?
Self-checkQuestion
Two admins open the same product. The second one saves changes based on a version the first admin has already replaced. Which status code fits best?
Self-checkQuestion
A browser loads one HTML page that references 2 CSS files, 3 JavaScript files and 5 images. At minimum, how many request–response cycles does it take (no cache)?
Self-checkQuestion
Which of these headers is not sent by the client?
Self-checkQuestion
Which two status codes are generated by a proxy or load balancer about the server behind it, rather than by your own code? (Choose two.)
Choose 2
Self-checkQuestion
An old URL has moved for good, and the redirect must work for every client. Which two status codes are permanent redirects? (Choose two.)
Choose 2
Self-checkQuestion
Which two statements about HTTP versions are true? (Choose two.)
Choose 2
Self-checkQuestion
Which two are real costs of the centralised client–server model? (Choose two.)
Choose 2