Chapter 1: HTTP vs WebSocket Differences: Why Do Chat Apps Need Real-Time Bidirectional Connections?
When developing traditional web applications, we almost always use the HTTP protocol. But when building "real-time interactive" applications (like Line chat rooms, stock trading software, or AI like ChatGPT where text appears character by character), traditional HTTP becomes painfully inadequate.
This chapter will take you through the underlying network protocol logic to understand why, for high-level commercial projects, you must step out of HTTP's comfort zone and embrace WebSocket and Streaming (SSE) technologies. This is also a necessary step in your journey from being a "junior web designer" to becoming a "full-stack architect."
🛑 Limitations of Traditional HTTP: Unidirectional and Short-Lived
The core model of HTTP (HyperText Transfer Protocol) is called the "Request-Response" model.
Imagine it like ordering a drink at a bubble tea shop:
- Request (Initiate): You (the frontend) walk up to the counter and say, "I'd like a pearl milk tea."
- Processing: The staff turns around to make the tea (the backend server is computing or querying the database).
- Response: The staff hands you the pearl milk tea.
Once the transaction ends, the "connection" between you and the staff is completely severed. This is called "Stateless."
If you want to ask, "Is there a new strawberry flavor now?", you can't just stand there waiting for the staff to tell you—you must "walk up to the counter and ask again."
The Fatal Performance Killer: Polling
What happens if we stubbornly use traditional HTTP to build a group chat?
Since the server "cannot actively" contact your webpage, your webpage has to set a timer to ask the server every second:
// Known as Short Polling - a performance disaster beginners often make
setInterval(async () => {
const response = await fetch('/api/get-new-messages?lastMsgId=999')
const newMessages = await response.json()
if (newMessages.length > 0) {
renderMessages(newMessages)
}
}, 1000) // Blindly hit the server every second
What catastrophic consequences does this bring?
- Too many invalid requests: If no one sends a message for 10 minutes, your webpage will still send 600
fetchrequests. - Server crashes instantly: With 10,000 online users, your server must handle 10,000 "Any new messages?" junk requests every second. The server's CPU and database connection pool will be exhausted instantly, leading to a crash (and you’ll receive a sky-high AWS or Vercel cloud bill).
⚡ The Birth of WebSocket: A Dedicated Bidirectional Hotline
To solve the performance disaster caused by polling, the WebSocket protocol was born in the HTML5 era.
WebSocket is like having a "dedicated hotline" between you and the server, and neither party hangs up.
It breaks HTTP's ironclad rule that "only the client can initiate requests!"
How WebSocket Works in Three Steps:
- Handshake Phase: The webpage sends an HTTP request to the server with a special header
Upgrade: websocket, asking, "Can we switch to WebSocket?" - Bidirectional Communication: Once the server agrees, the connection is established. Now, not only can the webpage send messages to the server at any time, but the server can also actively push messages (Push) to the webpage!
- Ultra-Low Latency: Unlike HTTP, which stuffs heavy headers (like Cookies, User-Agent) into every packet, WebSocket's data frames are extremely lightweight, making message delivery lightning-fast.
The Magic in Chat Apps
In a chat app scenario, when User A sends a "Hello" to the server, the server doesn’t need to wait for User B to ask—it can instantly broadcast "Hello" to B's screen through the already-established WebSocket hotline.
This is why, in Line, the moment someone hits send, your phone instantly shows a notification with zero delay.
🌊 The Foundation of Modern AI: Server-Sent Events (SSE) and Streaming
Besides WebSocket, another technology has become extremely popular in the AI (especially LLM) wave: Streaming and SSE (Server-Sent Events).
When using ChatGPT, you’ll notice its responses appear "character by character" in a typewriter effect.
Why can’t AI wait to generate the entire response before sending it all at once, like traditional HTTP?
The Physical Limits of AI Computation
Large language models (LLMs) have limited processing speeds. For a giant model like GPT-4, generating a 1000-word article might take 15 to 30 seconds.
With traditional HTTP, users would see a loading spinner and stare at a blank screen for 15 seconds. In modern web UX, if there’s no update for over 3 seconds, users assume "the site is broken" and close the tab.
So, the AI industry has fully adopted Streaming technology.
The server sends the first character as soon as it’s ready, pushing it through an unclosed connection. The second character follows, and so on. The frontend renders each character immediately, creating the illusion of "AI typing furiously."
How SSE (Server-Sent Events) Works Under the Hood
SSE is somewhat like WebSocket but uses traditional HTTP and is unidirectional.
- The webpage sends an HTTP GET/POST request to the server.
- The server responds with the header
Content-Type: text/event-stream, telling the browser: "I’m not done yet—don’t close this connection. I’ll keep sending new chunks." - The server can then continuously push new text over this connection.
This technology perfectly fits AI chat scenarios. After a user asks a question, they only need to "passively receive" the AI’s stream of responses, eliminating the need for a bidirectional WebSocket connection and significantly reducing server load.
🛠️ Modern Real-Time Tech Choices (Our Course Blueprint)
In summary, for building commercial-grade SaaS in 2024, you must choose the right real-time communication technology based on the scenario:
-
Supabase Realtime (WebSocket under the hood):
- Use Case: Monitoring database changes. E.g., "real-time group chat messages," "collaborative document editing," "live stock tickers."
- Advantage: Bidirectional, ultra-low latency.
-
AI Streaming API (Modern SSE variant):
- Use Case: Connecting to OpenAI/Anthropic servers to receive AI-generated text.
- Advantage: Lightweight, natively HTTP-compatible, perfect for Vercel AI SDK’s typewriter effect.
Ready? Theory class is over.
Next chapter, we dive into practice, starting with Supabase Realtime, to witness the magic of "zero polling code—frontend updates automatically when the database changes!"
WebSocket vs HTTP Polling
| Feature | HTTP Polling | WebSocket | |---------|-------------|-----------| | Connection | Opens and closes per request | Persistent, stays open | | Latency | Up to polling interval delay | Real-time (< 100ms) | | Server load | High (many requests) | Low (single connection) | | Bandwidth | Headers sent every request | Minimal overhead | | Bidirectional | Client→Server only | Full duplex | | Firewall friendly | ✅ Yes | ❌ May need config | | Scalability | Harder | Better |
WebSocket Lifecycle
Client Server
| |
|--- HTTP Upgrade Request -------->|
|<--- 101 Switching Protocols -----|
| |
|<--- WebSocket Connection Open ---|
| |
|--- Message (text/binary) ------>|
|<--- Message (text/binary) ------|
| |
|--- Ping ----------------------->|
|<--- Pong -----------------------|
| |
|--- Close Frame ----------------->|
|<--- Close Frame -----------------|
WebSocket in JavaScript
Client Side
const ws = new WebSocket('wss://api.example.com/ws');
// Connection opened
ws.onopen = () => {
console.log('Connected to WebSocket');
ws.send(JSON.stringify({ type: 'join', room: 'general' }));
};
// Receive messages
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Received:', data);
updateUI(data);
};
// Handle errors
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
// Connection closed
ws.onclose = (event) => {
console.log('Disconnected:', event.code, event.reason);
// Auto-reconnect after 3 seconds
setTimeout(() => connectWebSocket(), 3000);
};
// Send message
function sendMessage(text: string) {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'message', text }));
}
}
Server Side (Node.js + ws)
import { WebSocketServer } from 'ws';
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', (ws, req) => {
console.log('Client connected from:', req.socket.remoteAddress);
// Send welcome message
ws.send(JSON.stringify({ type: 'system', text: 'Welcome!' }));
// Handle incoming messages
ws.on('message', (data) => {
const message = JSON.parse(data.toString());
console.log('Received:', message);
// Broadcast to all connected clients
wss.clients.forEach((client) => {
if (client.readyState === ws.OPEN) {
client.send(JSON.stringify({
type: 'message',
user: message.user,
text: message.text,
timestamp: Date.now()
}));
}
});
});
// Handle disconnect
ws.on('close', () => {
console.log('Client disconnected');
});
});
console.log('WebSocket server running on port 8080');
Reconnection Strategies
| Strategy | Delay | Best For | |----------|-------|----------| | Fixed | 3 seconds | Simple apps | | Exponential backoff | 1s → 2s → 4s → 8s → 30s max | Production | | Linear | 5s, 10s, 15s... | Predictable retry | | Immediate | 0s (instant) | Critical connections |
Exponential Backoff Implementation
function connectWithBackoff(maxRetries = 10) {
let retries = 0;
function connect() {
const ws = new WebSocket('wss://api.example.com/ws');
ws.onopen = () => {
retries = 0;
console.log('Connected');
};
ws.onclose = () => {
retries++;
if (retries <= maxRetries) {
const delay = Math.min(1000 * Math.pow(2, retries - 1), 30000);
console.log(`Reconnecting in ${delay}ms (attempt ${retries})`);
setTimeout(connect, delay);
}
};
}
connect();
}
Summary
WebSocket provides real-time, bidirectional communication between client and server. It replaces HTTP polling for chat, live updates, and collaborative features.
Key takeaways:
- WebSocket: persistent connection, full duplex, low latency |
- HTTP polling: wasteful, high latency, high server load |
- Lifecycle: upgrade → open → messages → close |
- Client:
new WebSocket(url)with onopen, onmessage, onclose | - Server:
WebSocketServerfromwspackage | - Always implement reconnection with exponential backoff |
- WebSocket works on any platform with a WebSocket API |
- Use
ws.send()for sending,onmessagefor receiving |
What's Next: Building a Chat Server
The next chapter covers building a WebSocket chat server with Node.js.