HTTP Lifecycle
Trace the full journey of an HTTP request — from the moment a user clicks a link to the moment pixels appear on screen. Understand DNS, TCP, TLS, request/response structure, and where latency hides so you can optimize and debug like a pro.
Table of Contents
Overview
Every time you type a URL and press Enter, a complex chain of events fires behind the scenes — DNS lookup, TCP connection, optional TLS handshake, HTTP request, server processing, HTTP response, and finally browser rendering. The entire round trip typically takes 200–800ms, but each step can become a bottleneck.
Understanding this lifecycle is foundational for frontend system design. It explains why pages feel slow, where latency hides, and what you can optimize. It also connects every other topic in this roadmap — caching headers, CDNs, rendering pipelines — back to a single coherent flow.
"What happens when you type a URL into the browser?" is the most classic frontend interview question. A strong answer walks through each step with enough depth to show you understand the system, not just the surface.
Why this matters
This is the one topic that ties everything together. DNS, TCP, TLS, HTTP methods, status codes, caching, rendering — they all live on this timeline. Master the lifecycle and every other networking topic clicks into place.
High-Level Flow
Here is the complete journey of an HTTP request, from user action to rendered pixels. Each step happens sequentially — the next step can't start until the previous one completes.
User Action
The user types a URL, clicks a link, or JavaScript calls fetch(). The browser now needs to load a resource from a remote server.
DNS Resolution
The browser translates the domain name (e.g., example.com) into an IP address (e.g., 93.184.216.34). It checks caches first — browser, OS, router, ISP — before querying DNS servers.
TCP Connection
The browser opens a TCP connection to the server's IP address using a 3-way handshake (SYN → SYN-ACK → ACK). This establishes a reliable, ordered communication channel.
TLS Handshake (HTTPS only)
For HTTPS, the browser and server negotiate encryption. They exchange certificates, agree on a cipher suite, and generate session keys. This adds 1–2 extra round trips.
HTTP Request
The browser sends the HTTP request — method (GET/POST), headers (Host, Accept, Cookie), and optionally a body. This is the actual 'ask' for the resource.
Server Processing
The server receives the request, routes it, runs business logic, queries databases, and builds the response. This is the 'think' time — often the largest variable.
HTTP Response
The server sends back a status code (200, 404, 500), response headers (Content-Type, Cache-Control), and the response body (HTML, JSON, image bytes).
Browser Rendering
The browser parses HTML into a DOM, CSS into a CSSOM, builds the render tree, calculates layout, and paints pixels. For HTML pages, this triggers the critical rendering path.
User types "https://example.com/dashboard" ┌──────────────┐ │ User Action │ User presses Enter └──────┬───────┘ ▼ ┌──────────────┐ │ DNS Lookup │ example.com → 93.184.216.34 └──────┬───────┘ (~1-50ms, cached: <1ms) ▼ ┌──────────────┐ │ TCP Connect │ SYN → SYN-ACK → ACK └──────┬───────┘ (~1 round trip, ~20-100ms) ▼ ┌──────────────┐ │ TLS Handshk │ Certificate exchange + key negotiation └──────┬───────┘ (~1-2 round trips, ~30-150ms) ▼ ┌──────────────┐ │ HTTP Request│ GET /dashboard HTTP/2 └──────┬───────┘ Headers + optional body ▼ ┌──────────────┐ │ Server Work │ Route → Logic → DB → Build response └──────┬───────┘ (~10-500ms, highly variable) ▼ ┌──────────────┐ │ HTTP Response│ 200 OK + HTML body └──────┬───────┘ Headers + body streamed back ▼ ┌──────────────┐ │ Rendering │ Parse → DOM → CSSOM → Layout → Paint └──────────────┘ (~50-200ms for first paint) Total: ~150-1000ms for first meaningful paint
The key insight
Most of this time is spent waiting, not computing. Network latency (round trips between client and server) dominates. That's why optimizations like caching, CDNs, and connection reuse have such a massive impact — they eliminate round trips.
DNS Resolution
DNS (Domain Name System) translates human-readable domain names into IP addresses that computers use to find each other. It's the first step in every HTTP request — and it can be surprisingly slow if not cached.
How DNS Resolution Works
Browser cache
The browser checks its own DNS cache first. If you visited example.com recently, the IP is already stored. Cache duration is controlled by the DNS record's TTL (Time To Live).
OS cache
If not in the browser cache, the OS resolver is queried. The OS maintains its own DNS cache shared across all applications.
Router cache
Your home/office router often caches DNS responses too. This serves all devices on the local network.
ISP recursive resolver
If no local cache has the answer, the query goes to your ISP's DNS resolver. This server does the heavy lifting — querying root servers, TLD servers, and authoritative servers.
Authoritative DNS server
The final source of truth. The domain owner's DNS server returns the actual IP address. The result is cached at every level on the way back.
Browser: "What's the IP for example.com?" Browser cache → miss OS cache → miss Router cache → miss ISP resolver → miss │ ├─→ Root server: "Ask .com TLD server" ├─→ .com TLD: "Ask ns1.example.com" └─→ Authoritative: "93.184.216.34, TTL: 3600s" Response flows back, cached at every level: ISP resolver → cached (TTL: 3600s) Router cache → cached OS cache → cached Browser cache → cached Next request to example.com: <1ms (cache hit)
| Cache Level | Typical Latency | Scope |
|---|---|---|
| Browser cache | <1ms | Single browser instance |
| OS cache | <1ms | All apps on the machine |
| Router cache | ~1ms | All devices on the network |
| ISP resolver (cached) | ~5-20ms | All ISP customers |
| Full recursive lookup | ~50-200ms | Uncached, queries multiple servers |
Performance tip
Use <link rel="dns-prefetch" href="//api.example.com"> to resolve DNS for domains you'll need soon. This runs the lookup in the background so the connection is faster when the actual request fires.
Connection Establishment
Once the browser has the server's IP address, it needs to establish a connection. This involves a TCP handshake (always) and a TLS handshake (for HTTPS). Each handshake requires round trips between client and server.
TCP 3-Way Handshake
TCP provides reliable, ordered delivery of data. Before any data can flow, client and server must agree to communicate via a 3-step handshake.
Client Server │ │ │──── SYN (seq=100) ───────────→ │ Step 1: Client says "I want to connect" │ │ Sends initial sequence number │ │ │←─── SYN-ACK (seq=300,ack=101)──│ Step 2: Server says "OK, I acknowledge" │ │ Sends its own sequence number │ │ │──── ACK (ack=301) ───────────→ │ Step 3: Client confirms "Got it" │ │ Connection is now ESTABLISHED │ │ │←──── Data can now flow ───────→│ │ │ Cost: 1 round trip (SYN + SYN-ACK happen in parallel with ACK) Typical latency: 20-100ms depending on distance to server
TLS Handshake (HTTPS)
For HTTPS, after TCP is established, the browser and server negotiate encryption. TLS 1.3 (modern) requires 1 round trip; TLS 1.2 requires 2.
Client Server │ │ │── ClientHello ────────────────────→│ Supported cipher suites │ + key share │ + client's key share │ │ │←─ ServerHello + Certificate ────── │ Server's certificate │ + key share + Finished │ + server's key share │ │ + encrypted "Finished" │ │ │── Finished ───────────────────────→│ Client verifies certificate │ │ Both sides derive session keys │ │ │←═══ Encrypted data flows ════════→ │ │ │ TLS 1.3: 1 round trip (vs 2 for TLS 1.2) TLS 1.3 0-RTT: Returning visitors can send data immediately (using cached session keys from previous visit)
TCP Handshake
1 round trip. Establishes reliable, ordered connection. Required for all HTTP traffic. Cannot be skipped.
TLS 1.3
1 additional round trip. Negotiates encryption for HTTPS. Supports 0-RTT resumption for returning visitors.
Connection Reuse
HTTP keep-alive and HTTP/2 reuse existing connections, avoiding repeated handshakes. Massive performance win.
Total connection cost
For a first-time HTTPS visit: TCP (1 RTT) + TLS 1.3 (1 RTT) = 2 round trips before any data flows. At 100ms per round trip, that's 200ms just to establish the connection. This is why connection reuse and preconnect hints matter so much.
HTTP Request
With the connection established, the browser sends the actual HTTP request. Every request has three parts: a request line, headers, and an optional body.
GET /dashboard?tab=overview HTTP/2 ← Request line Host: example.com ← Headers start Accept: text/html,application/xhtml+xml Accept-Language: en-US,en;q=0.9 Accept-Encoding: gzip, deflate, br Cookie: session=abc123; theme=dark User-Agent: Mozilla/5.0 (Macintosh; ...) Connection: keep-alive Cache-Control: no-cache ← Empty line = end of headers ← No body for GET requests
HTTP Methods
| Method | Purpose | Has Body? | Idempotent? |
|---|---|---|---|
| GET | Retrieve a resource | No | Yes |
| POST | Create a resource / submit data | Yes | No |
| PUT | Replace a resource entirely | Yes | Yes |
| PATCH | Partially update a resource | Yes | No |
| DELETE | Remove a resource | Optional | Yes |
| HEAD | Same as GET but no response body | No | Yes |
| OPTIONS | Check allowed methods (CORS preflight) | No | Yes |
Key Request Headers
| Header | Purpose | Example |
|---|---|---|
| Host | Which domain the request is for | Host: example.com |
| Accept | What content types the client can handle | Accept: application/json |
| Authorization | Authentication credentials | Authorization: Bearer eyJhb... |
| Cookie | Session data from previous responses | Cookie: session=abc123 |
| Content-Type | Format of the request body | Content-Type: application/json |
| Cache-Control | Caching directives | Cache-Control: no-cache |
| Accept-Encoding | Supported compression algorithms | Accept-Encoding: gzip, br |
POST /api/users HTTP/2 Host: example.com Content-Type: application/json Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... Content-Length: 62 {"name":"Jane Doe","email":"jane@example.com","role":"admin"}
Interview note
Know the difference between idempotent and non-idempotent methods. GET, PUT, and DELETE are idempotent — calling them multiple times produces the same result. POST is not — each call may create a new resource. This matters for retry logic and caching.
Server Processing
The server receives the raw HTTP request and processes it through several layers before generating a response. This is often the most variable part of the lifecycle — it can take 5ms or 5 seconds depending on the work involved.
Load balancer / reverse proxy
In production, the request first hits a load balancer (e.g., Nginx, AWS ALB) that routes it to one of many backend servers. This adds ~1-5ms but enables horizontal scaling.
Web server receives request
The application server (Node.js, Django, Rails, etc.) parses the HTTP request — method, URL, headers, body — into a structured request object.
Middleware pipeline
The request passes through middleware: authentication checks, rate limiting, CORS validation, request logging, body parsing. Each middleware can modify the request or short-circuit with an error.
Route matching
The server matches the URL path and method to a handler function. GET /api/users/123 → getUserById(123).
Business logic
The handler executes application logic: validate input, check permissions, apply business rules, transform data.
Database / external services
Most handlers query a database or call external APIs. This is typically the slowest step — a database query can take 5-500ms depending on complexity and data size.
Build response
The handler constructs the HTTP response: status code, headers (Content-Type, Cache-Control, Set-Cookie), and body (HTML, JSON, binary data).
Request arrives at server │ ├─ Load balancer routing ~2ms ├─ Request parsing ~1ms ├─ Auth middleware ~5ms (JWT verification) ├─ Rate limit check ~1ms (Redis lookup) ├─ Route matching ~0.1ms ├─ Input validation ~1ms ├─ Database query ~15ms (SELECT * FROM users WHERE id = 123) ├─ Business logic ~2ms ├─ Response serialization ~1ms (JSON.stringify) │ └─ Total server processing: ~28ms Compare with network round trip: ~50-200ms Server processing is often LESS than network latency.
Where time actually goes
For most web applications, the server processing time is dominated by database queries and external API calls — not application code. A slow endpoint usually means a slow query, not slow JavaScript. Always profile the database first.
HTTP Response
The server sends back an HTTP response with three parts: a status line, headers, and a body. The status code tells the browser what happened; the headers control caching, cookies, and content negotiation; the body contains the actual data.
HTTP/2 200 OK ← Status line Content-Type: text/html; charset=utf-8 ← Headers start Content-Length: 14523 Content-Encoding: gzip Cache-Control: public, max-age=3600 Set-Cookie: session=xyz789; HttpOnly; Secure X-Request-Id: req_abc123 Date: Sun, 22 Mar 2026 10:30:00 GMT ← Empty line <!DOCTYPE html> ← Body starts <html lang="en"> <head><title>Dashboard</title>...</head> <body>...</body> </html>
Status Codes
| Range | Category | Common Codes |
|---|---|---|
| 1xx | Informational | 100 Continue, 101 Switching Protocols |
| 2xx | Success | 200 OK, 201 Created, 204 No Content |
| 3xx | Redirection | 301 Moved Permanently, 302 Found, 304 Not Modified |
| 4xx | Client Error | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Too Many Requests |
| 5xx | Server Error | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable |
Key Response Headers
| Header | Purpose | Example |
|---|---|---|
| Content-Type | Format of the response body | text/html; charset=utf-8 |
| Cache-Control | How the response should be cached | public, max-age=3600 |
| Set-Cookie | Store data on the client | session=xyz; HttpOnly; Secure |
| Content-Encoding | Compression used on the body | gzip |
| ETag | Version identifier for cache validation | ETag: "abc123" |
| Location | Redirect target (with 3xx status) | Location: /new-url |
| Access-Control-Allow-Origin | CORS permission | https://app.example.com |
304 Not Modified
When the browser has a cached version and sends If-None-Match or If-Modified-Since headers, the server can respond with 304 and no body — telling the browser to use its cached copy. This saves bandwidth and speeds up the response significantly.
Browser Rendering
Once the browser receives the HTML response, it begins the rendering pipeline. This is where the HTTP lifecycle connects to the critical rendering path — the response body becomes pixels on screen.
Parse HTML → DOM
The browser parses the HTML byte stream into a Document Object Model (DOM) tree. When it encounters <script> tags (without async/defer), parsing pauses until the script downloads and executes.
Parse CSS → CSSOM
CSS files and <style> blocks are parsed into a CSS Object Model (CSSOM). CSS is render-blocking — the browser won't paint until all CSS is parsed.
Build Render Tree
The DOM and CSSOM are combined into a render tree that contains only visible elements with their computed styles. Elements with display: none are excluded.
Layout (Reflow)
The browser calculates the exact position and size of every element in the render tree. This is where percentages, flexbox, and grid are resolved into pixel values.
Paint
The browser fills in pixels — text, colors, images, borders, shadows. Complex pages may be painted in multiple layers for compositing.
Composite
Layers are combined in the correct order and sent to the GPU for display. Transforms and opacity changes can be composited without repainting.
HTTP Response received (HTML bytes) │ ├─→ Parse HTML ──→ DOM Tree │ │ │ ├─ <link rel="stylesheet"> → fetch CSS → Parse → CSSOM │ ├─ <script src="..."> → fetch JS → Execute (blocks parsing!) │ └─ <img src="..."> → fetch image (non-blocking) │ ├─→ DOM + CSSOM ──→ Render Tree (visible elements + styles) │ ├─→ Layout ──→ Calculate positions and sizes │ ├─→ Paint ──→ Fill in pixels │ └─→ Composite ──→ Combine layers → Display Key events: • DOMContentLoaded: DOM is fully parsed (CSS/images may still load) • load: Everything is loaded (images, stylesheets, iframes) • First Contentful Paint (FCP): First text/image rendered • Largest Contentful Paint (LCP): Largest visible element rendered
The connection to HTTP
Every resource in the HTML (CSS, JS, images, fonts) triggers its own HTTP lifecycle — DNS, TCP, TLS, request, response. A page with 30 resources means 30 HTTP lifecycles. HTTP/2 multiplexing and connection reuse make this manageable by sharing a single connection for all requests to the same origin.
Real-World Example
Let's trace what actually happens when a user opens https://shop.example.com/products for the first time — with real timing estimates.
0ms User presses Enter ↓ 0-50ms DNS Resolution Browser cache: MISS (first visit) OS cache: MISS ISP resolver: MISS → full recursive lookup Result: 203.0.113.42 (cached for 3600s) ↓ 50ms TCP Handshake SYN → SYN-ACK → ACK Server is on a CDN edge node 30ms away ↓ 80ms TLS 1.3 Handshake ClientHello → ServerHello + Cert + Finished Session keys established ↓ 110ms HTTP Request Sent GET /products HTTP/2 Host: shop.example.com Accept: text/html Cookie: (none — first visit) ↓ 110-140ms Request travels to server (30ms) ↓ 140ms Server Processing → Nginx reverse proxy: 1ms → Node.js route matching: 0.5ms → Auth middleware: skipped (public page) → Redis cache check: 3ms → MISS → PostgreSQL query: 25ms SELECT * FROM products WHERE active = true ORDER BY created_at DESC LIMIT 20 → Template rendering: 5ms → Gzip compression: 2ms → Total: ~37ms ↓ 177ms HTTP Response Sent 200 OK Content-Type: text/html Content-Encoding: gzip Cache-Control: public, max-age=300 Transfer-Encoding: chunked Body: 45KB (14KB gzipped) ↓ 177-207ms Response travels back (30ms) ↓ 207ms Browser Starts Rendering → Parse HTML: discovers 3 CSS files, 2 JS bundles, 12 images → CSS requests fire (HTTP/2 multiplexed on same connection) → JS requests fire (defer attribute — non-blocking) ↓ 250ms First Contentful Paint (FCP) → Critical CSS loaded, header + skeleton visible ↓ 400ms Largest Contentful Paint (LCP) → Product images loaded, full page visible ↓ 450ms JavaScript Hydration Complete → Page is interactive Total time to interactive: ~450ms
Where the Time Goes
| Phase | Time | % of Total | Optimization |
|---|---|---|---|
| DNS lookup | 50ms | 11% | dns-prefetch, short TTL |
| TCP + TLS | 60ms | 13% | preconnect, HTTP/2, TLS 1.3 |
| Request travel | 30ms | 7% | CDN (reduce distance) |
| Server processing | 37ms | 8% | Caching, query optimization |
| Response travel | 30ms | 7% | CDN, compression |
| Rendering | 243ms | 54% | Critical CSS, defer JS, optimize images |
The takeaway
Rendering dominates — over half the time is spent parsing, loading sub-resources, and painting. Network setup (DNS + TCP + TLS) is the second biggest chunk. Server processing is often the smallest part. Optimize in order of impact: rendering first, then network, then server.
Performance Insights
Every step in the HTTP lifecycle is an optimization opportunity. The biggest wins come from eliminating round trips entirely — through caching, connection reuse, and CDNs.
DNS Prefetch & Preconnect
Use <link rel='dns-prefetch'> to resolve DNS early and <link rel='preconnect'> to establish TCP+TLS connections before they're needed. Saves 50-200ms per new origin.
HTTP/2 Multiplexing
HTTP/2 sends multiple requests over a single TCP connection simultaneously. No more head-of-line blocking. A page with 30 resources uses 1 connection instead of 6.
Connection Reuse (Keep-Alive)
HTTP keep-alive reuses TCP connections for multiple requests, avoiding repeated handshakes. HTTP/2 does this by default. Saves 1-2 round trips per subsequent request.
CDN (Content Delivery Network)
CDNs cache content at edge servers close to users. A request that would travel 200ms to the origin server takes 20ms to the nearest CDN edge. Reduces latency by 80-90%.
Compression (gzip / Brotli)
Compressing response bodies reduces transfer size by 60-80%. A 100KB HTML file becomes 20KB. Less data = faster transfer. Brotli compresses ~15-20% better than gzip.
HTTP Caching (Cache-Control, ETag)
Proper caching headers let the browser skip the entire HTTP lifecycle for cached resources. A cache hit takes <1ms vs 200ms+ for a network request. The fastest request is no request.
Resource Hints (preload, prefetch)
Use <link rel='preload'> for critical resources needed immediately and <link rel='prefetch'> for resources needed on the next page. Shifts work earlier in the timeline.
HTTP/1.1 vs HTTP/2 vs HTTP/3
| Feature | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Connections per origin | 6 parallel | 1 multiplexed | 1 multiplexed |
| Head-of-line blocking | Yes (per connection) | No (stream level) | No (per stream) |
| Header compression | None | HPACK | QPACK |
| Server push | No | Yes | Yes |
| Transport protocol | TCP | TCP | QUIC (UDP) |
| Connection setup | TCP + TLS (2-3 RTT) | TCP + TLS (2-3 RTT) | QUIC (1 RTT, 0-RTT resume) |
The fastest request is no request
Before optimizing any step in the lifecycle, ask: can I eliminate this request entirely? Cache it, inline it, or remove it. Every request you eliminate saves the entire lifecycle — DNS, TCP, TLS, server processing, and transfer time.
Common Mistakes
Too many requests to different origins
Each new origin requires DNS + TCP + TLS — 3 round trips before any data flows. A page loading resources from 10 different domains pays this cost 10 times.
✅Consolidate resources to fewer origins. Use a single CDN domain for static assets. Use preconnect hints for essential third-party origins.
Not compressing responses
Sending uncompressed HTML, CSS, and JS wastes bandwidth and increases transfer time. A 200KB JavaScript bundle takes 4x longer to transfer uncompressed.
✅Enable gzip or Brotli compression on your server/CDN. Brotli compresses 15-20% better than gzip for text resources. Check with curl -H 'Accept-Encoding: br'.
No caching headers on static assets
Without Cache-Control headers, the browser may re-fetch resources on every page load — repeating the entire HTTP lifecycle for files that haven't changed.
✅Set Cache-Control: public, max-age=31536000 for fingerprinted static assets (app.a1b2c3.js). Use ETag or Last-Modified for dynamic content that changes occasionally.
Render-blocking resources in the critical path
CSS files and synchronous scripts block rendering. The browser can't paint until all render-blocking resources complete their full HTTP lifecycle.
✅Inline critical CSS, defer non-critical CSS with media queries, and use async/defer on script tags. Move non-essential resources below the fold.
Serving from a single origin far from users
A server in US-East adds 200ms+ round trip for users in Asia or Europe. Every round trip (DNS, TCP, TLS, request) is multiplied by this distance.
✅Use a CDN to serve static assets from edge nodes close to users. For dynamic content, consider edge computing or regional server deployments.
Interview Questions
Q:What happens when you type a URL into the browser and press Enter?
A: The browser parses the URL, checks its cache, performs DNS resolution to get the server's IP, establishes a TCP connection (3-way handshake), negotiates TLS encryption for HTTPS, sends the HTTP request (method, headers, body), waits for the server to process and respond, then parses the HTML response and begins the rendering pipeline (DOM → CSSOM → Render Tree → Layout → Paint). Each sub-resource in the HTML triggers its own HTTP lifecycle.
Q:What is DNS and why does it matter for performance?
A: DNS translates domain names to IP addresses. It matters because it's the first step in every request to a new origin — a full recursive DNS lookup can take 50-200ms. The browser caches DNS results (controlled by TTL), and you can use dns-prefetch hints to resolve domains before they're needed. Reducing DNS lookups by consolidating origins is a key performance optimization.
Q:Explain the TCP 3-way handshake.
A: TCP requires a 3-step handshake before data can flow: (1) Client sends SYN with an initial sequence number, (2) Server responds with SYN-ACK acknowledging the client's sequence and providing its own, (3) Client sends ACK confirming the server's sequence. This costs 1 round trip and establishes a reliable, ordered connection. For HTTPS, a TLS handshake follows, adding 1-2 more round trips.
Q:What is the difference between HTTP and HTTPS?
A: HTTPS adds a TLS encryption layer on top of HTTP. After the TCP handshake, client and server perform a TLS handshake — exchanging certificates, agreeing on cipher suites, and generating session keys. All subsequent data is encrypted. HTTPS prevents eavesdropping, tampering, and impersonation. The cost is 1-2 extra round trips for the TLS handshake, though TLS 1.3 and session resumption minimize this.
Q:How does HTTP/2 improve performance over HTTP/1.1?
A: HTTP/2 introduces multiplexing — multiple requests and responses flow over a single TCP connection simultaneously, eliminating head-of-line blocking. It also adds HPACK header compression (reducing redundant header bytes), server push (sending resources before the client requests them), and stream prioritization. The result: fewer connections, less latency, and better utilization of each connection.
Q:What are the most impactful HTTP performance optimizations?
A: In order of impact: (1) Caching — eliminate requests entirely with proper Cache-Control headers, (2) CDN — reduce round trip time by serving from edge nodes, (3) Compression — gzip/Brotli reduces transfer size by 60-80%, (4) Connection reuse — HTTP/2 multiplexing avoids repeated handshakes, (5) Resource hints — dns-prefetch, preconnect, preload shift work earlier, (6) Minimize requests — bundle, inline critical resources, remove unnecessary dependencies.
Q:What is the difference between 301 and 302 redirects?
A: 301 (Moved Permanently) tells the browser and search engines that the resource has permanently moved — the browser caches this and goes directly to the new URL on future requests. 302 (Found) is a temporary redirect — the browser follows it but doesn't cache it, checking the original URL again next time. Use 301 for permanent URL changes (SEO transfers), 302 for temporary situations (maintenance, A/B testing).
Q:How does browser caching work with ETags?
A: When the server sends a response with an ETag header (a version identifier like a hash), the browser stores it. On subsequent requests for the same resource, the browser sends If-None-Match: <etag>. If the resource hasn't changed, the server responds with 304 Not Modified and no body — the browser uses its cached copy. This validates the cache without re-downloading the entire resource.
Practice Section
The Slow First Load
A user reports that your website takes 3 seconds to load on first visit but only 500ms on subsequent visits. The server response time is consistently 50ms. Where is the time going on the first visit, and why is the second visit faster?
Answer: First visit pays full cost: DNS resolution (~50ms), TCP handshake (~30ms), TLS handshake (~30ms), plus no cached resources — every CSS, JS, and image file triggers its own HTTP lifecycle. Second visit benefits from DNS cache, connection reuse (keep-alive), and browser HTTP cache (Cache-Control headers) — most resources are served from cache in <1ms.
The API Latency Mystery
Your API endpoint responds in 20ms (measured server-side), but the frontend measures 350ms from fetch() to response. The server is in US-East and the user is in Europe. What accounts for the 330ms difference?
Answer: Network round trip: ~120ms each way (US-East to Europe) = 240ms for request + response travel. Plus DNS resolution (~20ms if cached at ISP), TCP handshake (~120ms round trip), and TLS handshake (~120ms round trip) if it's a new connection. Solution: use a CDN or deploy an API edge in Europe, and ensure connection reuse with HTTP/2.
The Waterfall Problem
In DevTools Network tab, you see 40 requests loading sequentially (waterfall pattern) instead of in parallel. The page uses HTTP/1.1. What's happening and how would you fix it?
Answer: HTTP/1.1 limits browsers to ~6 parallel connections per origin. With 40 resources, they queue up in batches of 6. Fix: upgrade to HTTP/2 (multiplexes all requests over 1 connection), bundle resources to reduce request count, use a CDN (different origin = separate connection pool), or split assets across subdomains (domain sharding — HTTP/1.1 workaround).
The CORS Preflight Overhead
Your frontend makes a POST request with Content-Type: application/json to a different origin API. In the Network tab, you see TWO requests for every API call — an OPTIONS request followed by the actual POST. Why, and how can you reduce the overhead?
Answer: Cross-origin requests with non-simple headers (like Content-Type: application/json) trigger a CORS preflight OPTIONS request. The browser asks the server 'is this allowed?' before sending the real request. Fix: set Access-Control-Max-Age header on the OPTIONS response to cache the preflight result (e.g., 86400 = 24 hours). This eliminates the extra round trip for subsequent requests.
The Compression Win
Your page loads a 500KB uncompressed JavaScript bundle. The server supports gzip but it's not enabled. How much transfer time could you save by enabling compression, assuming a 10Mbps connection?
Answer: Gzip typically compresses JS by 60-70%, reducing 500KB to ~150KB. At 10Mbps: 500KB takes ~400ms to transfer, 150KB takes ~120ms — saving ~280ms. With Brotli, compression is even better (~75-80%), reducing to ~110KB and ~88ms transfer. Enable compression in your server config (nginx: gzip on) or CDN settings. This is one of the highest-ROI optimizations.
Cheat Sheet
Quick Revision Cheat Sheet
HTTP Lifecycle Order: User Action → DNS Resolution → TCP Handshake → TLS Handshake (HTTPS) → HTTP Request → Server Processing → HTTP Response → Browser Rendering.
DNS Resolution: Translates domain → IP. Cache chain: browser → OS → router → ISP → recursive lookup. Use dns-prefetch to resolve early. Full lookup: 50-200ms, cached: <1ms.
TCP 3-Way Handshake: SYN → SYN-ACK → ACK. Establishes reliable connection. Costs 1 round trip (~20-100ms). Required for all HTTP traffic.
TLS Handshake: Negotiates encryption for HTTPS. TLS 1.3: 1 round trip. TLS 1.2: 2 round trips. Supports 0-RTT session resumption for returning visitors.
HTTP Request: Method (GET/POST/PUT/DELETE) + Headers (Host, Accept, Cookie, Authorization) + optional Body. GET is idempotent, POST is not.
HTTP Response: Status code (2xx success, 3xx redirect, 4xx client error, 5xx server error) + Headers (Cache-Control, Set-Cookie, Content-Type) + Body.
Status Codes to Know: 200 OK, 201 Created, 204 No Content, 301 Permanent Redirect, 304 Not Modified, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Rate Limited, 500 Server Error.
HTTP/2 vs HTTP/1.1: HTTP/2: single multiplexed connection, HPACK header compression, server push, stream prioritization. Eliminates head-of-line blocking and connection limits.
Performance Priorities: 1) Cache (eliminate requests), 2) CDN (reduce distance), 3) Compress (reduce size), 4) Connection reuse (avoid handshakes), 5) Resource hints (shift work earlier).
Resource Hints: dns-prefetch: resolve DNS early. preconnect: DNS + TCP + TLS early. preload: fetch critical resource immediately. prefetch: fetch resource for next navigation.
The Fastest Request: Is no request at all. Cache with Cache-Control, inline critical CSS, bundle modules, eliminate unnecessary dependencies. Every eliminated request saves the full lifecycle.
Rendering Connection: Each sub-resource in HTML triggers its own HTTP lifecycle. CSS is render-blocking. Sync JS is parser-blocking. Images are non-blocking. Use async/defer for scripts.