The Future: HTTP/2 & WebSockets

The Future: HTTP/2 & WebSockets

Standard HTTP/1.1 was designed in 1997. The web has changed dramatically since then — we now load pages with hundreds of assets, stream video, build real-time collaborative tools, and expect sub-second responses. HTTP/2 and WebSockets were designed to meet these demands.


1. The Problem with HTTP/1.1

HTTP/1.1 introduced persistent connections (keep-alive), so you didn't need a new TCP connection for every request. But a single connection could only handle one request at a time:

HTTP/1.1 — Sequential (Head-of-Line Blocking):

Time ────────────────────────────────────────────────────────────────►
│
│  Connection 1:  [GET styles.css] ... [GET logo.png] ... [GET app.js]
│  Connection 2:  [GET fonts.woff] ... [GET icon.svg] ... [GET data.json]
│  Connection 3:  [GET hero.jpg]   ... [GET footer.jpg]
│
│  Browsers open 6 parallel connections MAX to one server
│  Each connection processes requests one at a time
│  → Large resources block all smaller ones behind them

This is called Head-of-Line (HOL) Blocking — like a queue at a checkout where one slow customer blocks everyone behind them.


2. HTTP/2 — The Multiplexed Highway

HTTP/2 (standardised in 2015) keeps a single TCP connection but allows multiple requests and responses interleaved on the same connection simultaneously.

HTTP/2 — Multiplexed (same TCP connection):

Time ────────────────────────────────────────────────────────────────►
│
│  Single Connection:
│    Stream 1:  [GET styles.css] ──────────────────►  [Response]
│    Stream 3:  [GET logo.png]   ─────────────────────────────►
│    Stream 5:  [GET app.js]     ──────────────────────►  [Response]
│    Stream 7:  [GET fonts.woff] ────────────────►  [Response]
│    Stream 9:  [GET data.json]  ────────────────────────────►
│
│  All streams in parallel on one connection
│  → No head-of-line blocking (at HTTP level)

Key HTTP/2 Features

FeatureWhat it doesBenefit
MultiplexingMultiple concurrent streams on one connectionEliminates HTTP-level HOL blocking
Header Compression (HPACK)Compresses and deduplicates headers across requestsHeaders that repeat (like auth tokens) are sent only once
Binary ProtocolUses binary frames instead of textFaster to parse, less error-prone
Stream PrioritisationClient hints which resources are most importantCritical CSS loads before non-critical images
Server PushServer proactively sends resources the client will needBrowser gets CSS/JS before it even parses the HTML

HTTP/2 vs HTTP/1.1 Performance

ScenarioHTTP/1.1HTTP/2
Page with 100 resources6 parallel connections, sequential per conn1 connection, all 100 in parallel
Repeated headers (identical auth)Sent in full on every requestOnly sent once (HPACK deduplication)
CSS/JS needed immediatelyBrowser discovers after parsing HTMLServer can push before browser asks

Server Push Example (Node.js)

// Using the 'http2' built-in Node.js module
const http2 = require('http2');
const fs    = require('fs');

const server = http2.createSecureServer({
  key:  fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt')
});

server.on('stream', (stream, headers) => {
  if (headers[':path'] === '/') {
    // Push CSS before the client asks for it
    stream.pushStream({ ':path': '/styles.css' }, (err, pushStream) => {
      pushStream.respondWithFile('./public/styles.css', {
        'content-type': 'text/css'
      });
    });

    // Serve the HTML page
    stream.respondWithFile('./public/index.html', {
      'content-type': 'text/html'
    });
  }
});

server.listen(443);

Note: Server Push has been largely deprecated in practice due to implementation complexity and the arrival of HTTP/3. The <link rel="preload"> HTML hint achieves similar results more simply.


3. HTTP/3 — The UDP Revolution

HTTP/2's multiplexing works at the HTTP level, but still runs over TCP. TCP itself has packet-level HOL blocking — if one TCP packet is lost, all HTTP/2 streams on that connection stall waiting for retransmission.

HTTP/3 solves this by running over QUIC instead of TCP.

HTTP/1.1 Stack:            HTTP/2 Stack:              HTTP/3 Stack:
  HTTP                       HTTP/2                     HTTP/3
    │                           │                          │
  TCP                         TCP                         QUIC (UDP-based)
    │                           │                          │
  IP                           IP                          IP
    │                           │                          │
  Physical                   Physical                   Physical

QUIC Features

FeatureBenefit
Built-in TLS 1.3Encrypted + connection established in 0-RTT on resumption
Per-stream loss recoveryDropped packet only affects its own stream — others continue
Connection migrationSwitch from Wi-Fi to 4G without reconnecting (same connection ID)
Reduced handshakeCombines TCP + TLS handshake into one round-trip
HTTP/2 over TCP — packet loss:

  Stream 1: [packet 1] [packet 2] [LOST packet 3] ... waiting ... [packet 4]
  Stream 3:                                          ↑ BLOCKED waiting for retransmit!
  Stream 5:                                          ↑ BLOCKED too!

HTTP/3 over QUIC — packet loss:

  Stream 1: [chunk 1] [chunk 2] [LOST chunk 3] ... waiting ... [chunk 4]
  Stream 3:                     → continues independently ✅
  Stream 5:                     → continues independently ✅

4. WebSockets — Real-Time Bidirectional Communication

Standard HTTP always follows the pattern: client asks → server answers. The server can never send data to a client that the client didn't ask for (known as "polling" workarounds).

WebSockets open a persistent, full-duplex (bidirectional) channel where:

  • The client can send to the server at any time
  • The server can send to the client at any time
  • No request-response pairing needed

WebSocket Handshake

WebSockets start as an HTTP connection, then upgrade:

Client → Server:
  GET /chat HTTP/1.1
  Host: chat.nandhoo.com
  Upgrade: websocket
  Connection: Upgrade
  Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
  Sec-WebSocket-Version: 13

Server → Client:
  HTTP/1.1 101 Switching Protocols
  Upgrade: websocket
  Connection: Upgrade
  Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

[HTTP connection is now a WebSocket connection]
[Data flows freely in both directions]

After the 101 Switching Protocols response, the connection is no longer HTTP — it's WebSocket frames until either side closes it.

WebSocket API in JavaScript

// Connect to a WebSocket server
const socket = new WebSocket('wss://chat.nandhoo.com/rooms/42');
//                            ^^^
//                            wss:// = WebSocket Secure (TLS)
//                            ws://  = WebSocket (plain, never use in production)

// Connection opened
socket.addEventListener('open', () => {
  console.log('WebSocket connected!');

  // Send a message to the server
  socket.send(JSON.stringify({
    type:    'join',
    room:    42,
    user:    'Alice',
    message: 'Hello everyone!'
  }));
});

// Receive messages from the server
socket.addEventListener('message', (event) => {
  const data = JSON.parse(event.data);
  console.log(`${data.user}: ${data.message}`);
  appendMessageToChat(data);
});

// Handle errors
socket.addEventListener('error', (err) => {
  console.error('WebSocket error:', err);
});

// Connection closed
socket.addEventListener('close', (event) => {
  console.log(`Disconnected. Code: ${event.code}, Reason: ${event.reason}`);

  if (event.code !== 1000) {
    // Reconnect after 3 seconds (exponential backoff in production)
    setTimeout(() => reconnect(), 3000);
  }
});

// Close the connection
function leaveChat() {
  socket.close(1000, 'User left the room'); // 1000 = normal closure
}

WebSocket Close Codes

CodeMeaning
1000Normal closure
1001Endpoint going away (browser navigating away)
1006Abnormal closure (connection dropped, no close frame)
1008Policy violation
1011Server encountered an unexpected error

5. Server-Sent Events (SSE) — One-Way Real-Time

SSE is a simpler alternative to WebSockets when you only need the server to push data to the client (not the other way).

// Client: subscribe to a stream of events
const eventSource = new EventSource('https://api.nandhoo.com/events/live-scores');

eventSource.addEventListener('score', (event) => {
  const score = JSON.parse(event.data);
  updateScoreboard(score);
});

eventSource.addEventListener('error', () => {
  console.log('Connection lost, browser will reconnect...');
});

// Stop listening
function stopWatching() {
  eventSource.close();
}

Server sends (plain HTTP response with text/event-stream content type):

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache

event: score
data: {"team":"A","points":42}

event: score
data: {"team":"B","points":38}

SSE vs WebSockets

SSEWebSockets
DirectionServer → Client onlyBidirectional
ProtocolHTTPWebSocket (after upgrade)
Auto-reconnect✅ Built-in❌ Must implement manually
Text only✅ Text/UTF-8Text and binary
CORS support✅ Standard✅ With origin checks
Proxy/firewall friendly✅ (plain HTTP)⚠️ Some proxies block WS
Best forLive feeds, notifications, progressChat, games, collaboration

6. Long Polling — The HTTP/1.1 Workaround

Before WebSockets were widely supported, developers used long polling:

// Long Polling approach (legacy — avoid if WebSockets are available)
async function poll() {
  try {
    // Server holds the request open for up to 30 seconds
    // If new data arrives, it responds immediately
    // If timeout, it returns empty and client re-polls
    const res  = await fetch('/api/updates?last=1711864280');
    const data = await res.json();

    if (data.updates.length > 0) processUpdates(data.updates);
  } finally {
    // Immediately poll again
    setTimeout(poll, 100);
  }
}

poll();

Problems with long polling:

  • Wastes server resources keeping connections open
  • Still has the request-response overhead
  • Hard to handle reconnections and errors

Use WebSockets or SSE instead for real-time applications.


7. Choosing the Right Technology

Do you need real-time updates?
│
├── No → Use regular HTTP fetch/REST APIs
│
└── Yes → Do you need bidirectional communication?
           │
           ├── Yes → WebSockets
           │         Examples: chat, multiplayer games, collaborative editors
           │                   live coding environments, trading dashboards
           │
           └── No → Server-Sent Events (SSE)
                    Examples: live notifications, progress tracking, live scores
                              news feeds, stock tickers, deployment logs

8. A Full Chat Application Example

class ChatRoom {
  constructor(roomId, username) {
    this.roomId   = roomId;
    this.username = username;
    this.socket   = null;
    this.retries  = 0;
  }

  connect() {
    this.socket = new WebSocket(
      `wss://chat.nandhoo.com/rooms/${this.roomId}`
    );

    this.socket.onopen = () => {
      this.retries = 0;
      this.send({ type: 'join', username: this.username });
    };

    this.socket.onmessage = ({ data }) => {
      const msg = JSON.parse(data);
      switch (msg.type) {
        case 'message':  this.displayMessage(msg);    break;
        case 'presence': this.updatePresence(msg);    break;
        case 'typing':   this.showTypingIndicator(msg); break;
      }
    };

    this.socket.onclose = (event) => {
      if (event.code !== 1000 && this.retries < 5) {
        const delay = Math.min(1000 * 2 ** this.retries, 30000); // Exponential backoff
        console.log(`Reconnecting in ${delay}ms...`);
        setTimeout(() => { this.retries++; this.connect(); }, delay);
      }
    };

    this.socket.onerror = (err) => console.error('WS error', err);
  }

  send(data) {
    if (this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(JSON.stringify(data));
    }
  }

  sendMessage(text) {
    this.send({ type: 'message', text, username: this.username });
  }

  disconnect() {
    this.retries = 5; // Prevent reconnection
    this.socket?.close(1000, 'Left the room');
  }

  displayMessage({ username, text, timestamp }) {
    const div = document.createElement('div');
    div.className = username === this.username ? 'mine' : 'theirs';
    div.innerHTML = `<strong>${username}</strong>: ${text}`;
    document.querySelector('#messages').appendChild(div);
  }

  updatePresence({ users }) {
    document.querySelector('#users').textContent = users.join(', ');
  }

  showTypingIndicator({ username }) {
    document.querySelector('#typing').textContent = `${username} is typing...`;
    setTimeout(() => document.querySelector('#typing').textContent = '', 3000);
  }
}

const room = new ChatRoom(42, 'Alice');
room.connect();

9. HTTP Version Comparison

FeatureHTTP/1.1HTTP/2HTTP/3
Year199720152022
TransportTCPTCPQUIC (UDP)
MultiplexingNo (HOL blocking)Yes (streams)Yes (per-stream)
Header formatTextBinary + HPACK compressionBinary + QPACK compression
TLS requiredOptionalEffectively requiredAlways (built-in)
Server PushNoYes (deprecated)No
Connection migrationNoNoYes (mobile!)
Adoption (2024)~20%~35%~30%

10. Mini Exercises

  1. Open DevTools → Network tab → Check the "Protocol" column. What HTTP version does Google.com use? Your bank?
  2. In the console, open a WebSocket to the free echo server: new WebSocket('wss://echo.websocket.events'). Listen for messages and send one with .send('Hello from Nandhoo!').
  3. Subscribe to an SSE stream: new EventSource('https://sse.dev/test'). What events arrive?
  4. Read about HTTP/3 on cloudflare.com. Which feature do you think is most impactful for mobile users and why?
  5. Build a simple typing indicator: use a WebSocket to broadcast "typing" events when a user types, and show it on the screen.

11. Key Terms

TermMeaning
HOL BlockingHead-of-Line Blocking — one slow request blocks all requests behind it
MultiplexingMultiple concurrent HTTP streams over a single connection
HPACKHeader compression algorithm used in HTTP/2
QUICUDP-based transport protocol used by HTTP/3
Server PushServer proactively sending resources before the client asks
WebSocketFull-duplex, persistent connection — both sides can send anytime
SSEServer-Sent Events — one-way real-time stream from server to client
101 Switching ProtocolsHTTP status upgrading the connection to WebSocket
wss://WebSocket Secure — WebSocket over TLS
Long PollingLegacy real-time technique — client keeps re-requesting until data arrives
Exponential BackoffReconnection strategy — double the wait time after each failure

Congratulations! You've completed the HTTP & Networking module. You now understand the full journey of data from client to server and back, encrypted and secure.

Back to Introduction: HTTP & Networking Overview