The HTTP Request Lifecycle: DNS Lookup, TCP Connection, Request, Response

~13 min read

Every HTTP request goes through the same four stages: find the server's address (DNS), open a reliable connection (TCP), send the request, and receive the response — worth understanding since each stage is a place things can be slow or fail.

The previous subtopic sketched 'the browser sends a request, the server sends back a response' at a high level. This subtopic zooms into what actually happens in between, because each of these stages is a real place where requests can be slow, or fail, in ways worth being able to recognize.

Stage 1: DNS lookup. Computers address each other by numeric IP addresses (like 142.250.80.46), not human-readable names — but you type 'google.com,' not a number. DNS (Domain Name System) is the internet's phonebook: your computer asks a DNS server 'what IP address does google.com point to right now,' gets back the numeric address, and caches that answer briefly so it doesn't have to ask again for every single request. This lookup happens before anything else can proceed — you can't connect to a server whose address you don't know yet.

Stage 2: TCP connection. Once your computer has the server's IP address, it opens a TCP connection to it — TCP (Transmission Control Protocol) is the underlying layer that guarantees data arrives reliably and IN ORDER, handling the unglamorous but essential job of retransmitting anything that gets lost or corrupted along the way. This involves a 'handshake' (a brief back-and-forth to establish the connection) before any actual data flows. For encrypted connections (HTTPS, the norm for essentially all real traffic today), there's an additional TLS handshake layered on top, which negotiates encryption keys so nobody eavesdropping on the network can read the actual request/response content.

Stage 3: HTTP request. With a connection established, your client sends the actual HTTP request — the method, path, headers (including the Authorization header from the api-basics unit), and body, exactly as covered in the REST fundamentals subtopic. This is the part that actually specifies WHAT you want.

Stage 4: HTTP response. The server processes the request and sends back its response over that same connection — status code, headers, and body, which your client then reads and acts on (for a browser, this typically means rendering HTML; for API-calling code, it typically means parsing the JSON body).

Understanding these four stages matters practically because they explain WHERE latency comes from: a slow DNS server adds delay before anything else even starts; a fresh TCP+TLS handshake adds delay especially over a poor connection (which is why connections are often kept open and REUSED across multiple requests rather than reconnecting every time); and the actual request/response transfer is only the final stage, not the whole story of 'why did that API call take so long.'

💻 Code example

# Manually walking through the first two stages (DNS + TCP) that
# normally happen invisibly inside a single requests.get() call.
import socket
import time

hostname = "example.com"

# Stage 1: DNS lookup -- translate the name into an IP address
start = time.perf_counter()
ip_address = socket.gethostbyname(hostname)
dns_time = (time.perf_counter() - start) * 1000
print(f"DNS lookup: {hostname} -> {ip_address}  ({dns_time:.1f}ms)")

# Stage 2: TCP connection -- open a reliable connection to that IP, port 80
start = time.perf_counter()
sock = socket.create_connection((ip_address, 80), timeout=5)
tcp_time = (time.perf_counter() - start) * 1000
print(f"TCP connection established  ({tcp_time:.1f}ms)")

# Stage 3: HTTP request -- send the actual request over that connection
request = f"GET / HTTP/1.1\r\nHost: {hostname}\r\nConnection: close\r\n\r\n"
sock.sendall(request.encode())

# Stage 4: HTTP response -- read what the server sends back
response = sock.recv(200).decode(errors="replace")
print(f"Response starts with: {response.splitlines()[0]!r}")
sock.close()

# In real code, `requests.get(f"http://{hostname}")` does all 4 stages
# in one call -- this just makes each stage, and its own latency, visible

💬 Deep Dive with AI

Key points

  • DNS lookup translates a human-readable name (google.com) into a numeric IP address — the very first stage, since you can't connect without an address
  • TCP connection establishment guarantees reliable, in-order delivery via a handshake; HTTPS adds a further TLS handshake to negotiate encryption
  • The HTTP request stage sends the method, path, headers (including auth), and body — the actual 'what do you want' from the REST fundamentals subtopic
  • The HTTP response stage returns status code, headers, and body, which the client then parses (render HTML, or parse JSON for an API call)
  • Each stage is a real source of latency — DNS delays, fresh TCP/TLS handshakes — which is why connections are often reused across multiple requests instead of reconnecting each time