WebSockets: When HTTP Isn't Enough
HTTP is request-response: the client asks, the server answers. But for real-time features — chat, live notifications, collaborative editing, live dashboards — you need the server to push data to the client without being asked. That's WebSockets.
HTTP vs WebSocket
| Feature | HTTP | WebSocket |
|---|---|---|
| Communication | Request → Response | Bidirectional |
| Connection | New connection per request | Persistent connection |
| Overhead | Headers on every request | Minimal after handshake |
| Server push | Not native (polling, SSE) | Native |
| Protocol | HTTP/1.1, HTTP/2 | ws:// or wss:// |
The Handshake
// Client sends HTTP upgrade request
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
// Server responds
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
// Now both sides can send messages freelyBrowser API
const ws = new WebSocket('wss://example.com/chat');
ws.onopen = () => {
console.log('Connected');
ws.send(JSON.stringify({ type: 'join', room: 'general' }));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Received:', data);
};
ws.onclose = (event) => {
console.log('Disconnected:', event.code, event.reason);
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};Server Implementation (Node.js)
// Using the 'ws' library
import { WebSocketServer } from 'ws';
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', (ws) => {
console.log('Client connected');
ws.on('message', (data) => {
const message = JSON.parse(data);
// Broadcast to all clients
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(message));
}
});
});
ws.on('close', () => {
console.log('Client disconnected');
});
});Socket.IO (Batteries Included)
// Server
import { Server } from 'socket.io';
const io = new Server(3000, { cors: { origin: '*' } });
io.on('connection', (socket) => {
socket.join('room:general');
socket.on('chat:message', (msg) => {
io.to('room:general').emit('chat:message', {
user: socket.id,
text: msg,
timestamp: Date.now(),
});
});
});
// Client
import { io } from 'socket.io-client';
const socket = io('http://localhost:3000');
socket.on('chat:message', (msg) => {
console.log(msg);
});
socket.emit('chat:message', 'Hello!');When to Use What
| Technique | Best For | Complexity |
|---|---|---|
| WebSocket | Chat, gaming, live collaboration | Medium |
| SSE (Server-Sent Events) | One-way server → client (notifications, feeds) | Low |
| HTTP Polling | Simple status checks, low frequency | Lowest |
| HTTP Long Polling | Fallback when WebSocket/SSE unavailable | Low |
If the client only needs to receive updates (not send), consider SSE — it's simpler, works over HTTP, and auto-reconnects.
Test your APIs: HTTP Reference — status codes and headers reference.