WebSocket Clients: JavaScript
This guide explains how to create, manage, and secure a WebSocket client in modern JavaScript. It includes connection setup, message handling, reconnection logic, and best practices for real-time apps.
π 1. Basic WebSocket Client
const socket = new WebSocket("wss://your-api.com/ws");
socket.onopen = () => {
console.log("Connected to WebSocket");
};
socket.onmessage = (event) => {
const msg = JSON.parse(event.data);
handleMessage(msg);
};
socket.onclose = (event) => {
console.log("Disconnected:", event.code, event.reason);
};
socket.onerror = (error) => {
console.error("WebSocket error:", error);
};
π¨ 2. Sending Messages
Always follow your backendβs message format (e.g. include type
and data
).
function sendMessage(type, data) {
const message = {
type,
data,
meta: {
request_id: crypto.randomUUID(),
timestamp: new Date().toISOString(),
},
};
socket.send(JSON.stringify(message));
}
Example:
π 3. Reconnection Logic
Add automatic reconnection with exponential backoff.
let reconnectAttempts = 0;
function connect() {
const ws = new WebSocket("wss://your-api.com/ws?token=YOUR_TOKEN");
ws.onopen = () => {
reconnectAttempts = 0;
console.log("WebSocket connected");
};
ws.onclose = (event) => {
console.warn("WebSocket closed:", event.code);
const timeout = Math.min(1000 * 2 ** reconnectAttempts, 30000);
setTimeout(connect, timeout);
reconnectAttempts++;
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
handleMessage(msg);
};
ws.onerror = (e) => console.error("WebSocket error:", e);
}
connect();
π 4. Authentication
Most secure apps use a token in the query string or send an auth message after connection:
With token in URL:
const token = getTokenFromStorage();
const socket = new WebSocket(`wss://your-api.com/ws?token=${token}`);
Or: send token in first message:
π§ 5. Handling Server Messages
Structure your message handler based on type
.
function handleMessage(msg) {
switch (msg.type) {
case "connection_established":
console.log("Connected:", msg.data);
break;
case "new_message":
displayChatMessage(msg.data);
break;
case "user_typing":
showTypingIndicator(msg.data.user_id);
break;
case "error":
alert("Error: " + msg.data.message);
break;
default:
console.warn("Unknown event type:", msg.type);
}
}
π§ͺ 6. Debugging Tips
- Use browser DevTools β Network > WS tab to inspect messages.
- Log all
onmessage
andonerror
events during development. - Retry connections only after handling auth or network errors properly.
- Throttle reconnection attempts to avoid flooding the server.
β 7. Best Practices
- Always use
wss://
in production for encryption. - Abstract socket logic into a reusable class or hook.
- Handle all close codes gracefully (e.g.,
1008
for auth failure). - Implement ping/pong logic if required by the backend.
- Track connection state for UI updates (e.g., loading spinners, reconnect notices).
π¦ 8. Optional: WebSocket Wrapper Class
class WSClient {
constructor(url) {
this.url = url;
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => console.log("Connected");
this.ws.onclose = () => setTimeout(() => this.connect(), 3000);
this.ws.onmessage = (e) => this.onMessage(JSON.parse(e.data));
this.ws.onerror = (e) => console.error(e);
}
send(type, data) {
this.ws.send(JSON.stringify({ type, data }));
}
onMessage(msg) {
console.log("Received:", msg);
// Dispatch to handlers here
}
}
π Next Steps
- Message Format: Follow the standardized structure for all messages.
- Authentication: Secure your WebSocket sessions.
- Disconnection Handling: Manage graceful reconnections and state.