
To understand how web servers handle requests, picture a program that waits on a network port, receives your browser's message, works out what you want, fetches the data and sends back an answer. Every click you make starts that cycle on a machine you'll never see, and it runs in the same order every time: receive, parse, route, process, respond.
This matters because a slow or broken page usually means one of those steps went wrong. When you know the steps, you can work out which one failed instead of guessing. Below, we follow a single request from the moment it leaves your browser to the moment the response comes back, then look at how servers handle many requests at once and the mistakes that most often break them.
- A web server is a program that listens on a port and answers every request with a page, JSON or an error.
- The request first travels over a TCP connection, usually secured with TLS, before any HTTP is sent.
- The server parses raw text into a request object, passes it through middleware, then routes it to one handler.
- The handler fetches data from caches or databases and builds the response the client sees.
- Servers handle many requests at once using threads, processes or an event loop, and often a mix of them.
- 0:00Intro
- 0:22When a page just hangs
- 1:06A server listens and responds
- 1:52One central place for many clients
- 2:38The request arrives over TCP and TLS
- 3:19Turning bytes into a request
- 4:17Middleware, then the right handler
- 5:19The handler does the work
- 6:10Follow one product page request
- 7:01Threads, processes, or an event loop
- 7:50The same steps, everywhere
- 8:30Three ways servers break
- 9:28The request cycle in five points
- 9:56Receive, route, process, respond
What is a web server, and what does it actually do?
A web server isn't a magic box. It's a program running on a machine that listens for requests and sends back responses. The waiting part matters: the server sits idle on a network port, such as 443, until a client connects. Your browser sends an HTTP request, the server does its work, and an HTTP response travels back to the browser.
Listening means the program has opened a port and is waiting for connections. Nginx, Apache and a Node app all start this same way before they can serve anything. Responding means every request gets an answer, whether that's a web page, some JSON or an error code. The practical lesson is simple: a request that never gets a response is always a bug somewhere.
Keeping this model in mind changes how you read failures. A spinning page doesn't tell you much on its own. A slow page often means the server is waiting on slow work behind it, such as a long database query, even though the request itself arrived without trouble. A timeout means someone stopped waiting, and that could be the browser, a proxy or the server itself.
- Listens: opens a port and waits for connections
- Responds: returns a page, JSON or an error for every request
- A request with no response points to a bug
Why do apps use a central server at all?
Many clients need the same data and the same rules. Keeping one copy in one central place is much simpler than copying it to every device. Think of a library: everyone borrows from one shelf instead of owning every book. A phone app, a laptop and a tablet can all send requests to the same server and get answers from the same source of truth.
Shared data means one database holds, for example, your orders, so your phone and your laptop always show the same list. You update it once and every client sees the change. Shared logic means rules such as prices or permissions live in one spot. If you fix a bug on the server, every client gets the fix at once, with no app update needed.
Step 1: How a request reaches the server over TCP and TLS
Before any HTTP is sent, the client and server open a TCP connection, and they usually secure it with TLS. The order matters, because HTTP only travels once the connection is ready. First comes the TCP handshake: the browser sends SYN, the server answers with SYN-ACK, and the browser replies with ACK. At that point a reliable connection is open.
Next, TLS sets up encryption. The browser sends a ClientHello, and the server answers with a ServerHello plus its certificate. Only after that does the actual request, such as GET /products, cross the wire, and it does so encrypted. An encrypted channel means nobody between you and the server can read or change the request.
This step also explains a specific kind of error. If the TLS part fails, you see a certificate error before any of the server's own application code has run. That's a useful clue: the problem lies in the connection setup, not in the page logic.
- TCP handshake: SYN → SYN-ACK → ACK
- TLS: ClientHello → ServerHello + certificate
- Then the encrypted HTTP request is sent
Step 2: Parsing raw bytes into a request object
Once the bytes arrive, the server has to make sense of them. Parsing turns raw HTTP text into a structured request with a method, a path, headers and a body. Your framework usually handles this for you, but it happens on every single request. Take a login: the request line reads POST /login HTTP/1.1, which tells the server what kind of request this is.
After the request line come the headers, split on newlines, such as Host, Cookie and Accept. A blank line follows, then the body, which for a login form holds the username and password. The parser bundles all of this into one request object that the rest of the server code can use.
The method and path together say what you want and where. POST means submit something, and /login names the target. That pair becomes the key for routing in the next step. Headers and body carry the details: cookies, content type and form data. If the input is malformed, the server catches it here and replies with 400 Bad Request.
Step 3: How middleware and routing pick the right handler
With a clean request object in hand, the server routes it. The request first passes through a chain of middleware, then the router hands it to the one handler that matches its method and path. It works a bit like airport security before the boarding gate: shared checks happen first, then you go to one specific place.
Middleware is code that runs on every request, or on a group of them. Logging, authentication and compression are typical examples. A logger records each request, and an auth step checks the session cookie. You write this code once instead of repeating it in every handler. Middleware can also short-circuit, ending a request early so it never reaches a handler at all.
The routing table maps method-and-path pairs to handlers. For example, GET /products goes to the product function. If nothing in the table matches, the server returns 404 Not Found. This is why a 404 usually means the route doesn't exist, not that the server is down.
- Middleware: shared code such as logging, auth and compression
- Routing table: maps method and path to one handler
- Short-circuit: middleware can stop a request early
- No match in the table: 404 Not Found
Step 4: What the handler does with the request
The handler is where your own logic lives. It fetches what it needs, builds a response and sends it back over the same connection. A large share of a request's time is often spent right here, waiting on data. A common setup has the handler check a cache such as Redis first, because reading from memory is fast.
On a cache miss, the handler queries the database, PostgreSQL for instance, and can store the result in the cache for next time. A cache hit skips the database entirely, which keeps busy endpoints fast and takes load off the main data store. Building the response means choosing a status code, setting headers like Content-Type and writing the body as HTML or JSON. That finished package is the only thing the client ever sees.
Here's the whole path for one real case: opening a product page in an online shop, which asks for product 42. Receive: TCP and TLS open on port 443. Parse: GET /products/42. Route: the router picks productHandler. Query: Redis misses, so it falls back to SQL. Respond: 200 OK with JSON holding the product details. The HTML, the API calls and even images, if the same server serves them, each take this path, many at the same time.
- Time each stage before you optimise
- If the query step dominates, an index or a cache helps more than a faster server
How do web servers handle many requests at once?
A single request is only part of the picture. A real server handles many at the same time, and there are three main ways to do it: threads, processes or an event loop. None of them is always best. Each one suits a different kind of workload and has its own weak spot.
With threads, the server uses one thread per request. Threads share memory and need locks, and their memory use adds up. Apache and Java servers are familiar examples. With processes, separate worker processes handle requests, so a crash only takes down one worker, though processes are heavier to start. Gunicorn works this way. An event loop uses one loop to manage many sockets. Node.js and Nginx use this model, and its weak spot is that a blocking call stalls the whole loop.
In practice, servers often mix and match. Nginx runs an event loop inside several worker processes, which gives it both the isolation of processes and the efficiency of an event loop.
- Threads: shared memory, needs locks, memory adds up
- Processes: crashes stay in one worker, heavier to start
- Event loop: one loop for many sockets, stalled by blocking calls
Where you'll see the same request cycle
Once you know the cycle, you start noticing it everywhere. Almost anything that answers over HTTP follows the same four steps, whatever language or framework it uses. Only the response format changes. Websites return HTML, public APIs return JSON, and mobile backends sit behind the apps on your phone.
Webhooks that other services call and internal services that talk to each other inside a company follow the same pattern too. Receive, route, process, respond applies every time. That's why learning a new framework gets easier: it's just another way of writing the same cycle.
- Websites
- Public APIs
- Mobile backends
- Webhooks
- Internal services
Three common mistakes that make servers slow or unsafe
Most server problems aren't exotic. They usually come from three common mistakes: blocking calls, missing timeouts and trusting input. All three tend to hide during testing on your own machine. With one user, everything feels fine. With many users under real traffic, requests get stuck and the server falls over.
Blocking calls, like synchronous file reads or slow network calls on an event loop, freeze every other request. Use async calls, or move heavy work into a background job. Missing timeouts let a stuck database or API hold connections open until the server runs out of them. Set a timeout on every outbound call and on incoming requests.
Trusting input opens the door to SQL injection and corrupted data. Validate everything during parsing and use parameterised queries. The rule is simple: never trust what arrives from the client until you have checked it.
- Blocking calls: one slow call freezes other requests
- Missing timeouts: stuck calls hold connections forever
- Trusting input: validate and use parameterised queries
Key takeaways
- A web server listens on a port and answers every request, and a request with no response is a bug.
- TCP and TLS come first, so certificate errors appear before your server code runs.
- Parsing produces the method, path, headers and body, and catches malformed input with 400 Bad Request.
- Middleware handles shared checks, and the routing table sends each request to one handler or returns 404.
- Handlers often check a cache before the database, and that waiting is where much of the time goes.
- Blocking calls, missing timeouts and trusted input cause most real-world server failures.
Frequently asked questions
What happens when I type a URL and press Enter?
Your browser opens a TCP connection to the server, usually secures it with TLS, then sends an HTTP request. The server parses it, routes it to a handler, fetches any data it needs and sends back a response such as HTML or JSON.
Why does a page load slowly even when my internet is fine?
Often the request reached the server without trouble, but the server is waiting on slow work behind it, such as a long database query. Timing each stage of the request shows where the delay actually is.
What is the difference between a 400 and a 404 error?
A 400 Bad Request means the server couldn't make sense of the request during parsing, for example because the input was malformed. A 404 Not Found means the request was readable, but no route matched its method and path.
What is middleware in a web server?
Middleware is code that runs on every request, or on a group of requests, before the handler. Logging, authentication and compression are common examples, and middleware can also stop a request early.
Is an event loop better than threads for a web server?
Not always. Threads, processes and event loops each suit different workloads and have different weak spots, such as a blocking call stalling an event loop. Many real servers, including Nginx, combine models.
Why do timeouts matter so much on a server?
Without them, a stuck database or external API can hold connections open until the server runs out of them. Setting timeouts on outbound calls and incoming requests stops one slow dependency from freezing everything.