Como criar chats, notificações e dashboards ao vivo com WebSockets

Como criar chats, notificações e dashboards ao vivo com WebSockets
Resumo: Este artigo demonstra, de forma prática e detalhada, como usar WebSockets para construir aplicações que exigem comunicação em tempo real, como chats, notificações push e painéis de monitoramento. Abordaremos a arquitetura recomendada, questões de segurança, estratégias de escalabilidade e apresentaremos exemplos de código funcionais em Node.js e Python.
Introdução
A necessidade de interatividade instantânea tem impulsionado a adoção de WebSockets em aplicações modernas. Diferente das requisições HTTP tradicionais, que seguem o modelo request‑response, o WebSocket estabelece um canal bidirecional persistente entre cliente e servidor. Essa conexão permite a troca de mensagens com latência mínima, ideal para:
- Chats onde cada mensagem deve aparecer imediatamente para todos os participantes.
- Notificações push que avisam o usuário sobre eventos críticos (ex.: nova ordem, alerta de segurança).
- Dashboards live que exibem métricas de sistemas, preço de ativos financeiros ou status de dispositivos IoT em tempo real.
1. Arquitetura básica de um sistema WebSocket
1.1 Componentes principais
| Componente | Função | Tecnologias típicas |
|---|---|---|
| Cliente | Abre a conexão, envia e recebe mensagens. | JavaScript (browser), React Native, Flutter |
| Servidor WebSocket | Mantém sockets ativos, roteia mensagens e aplica lógica de negócios. | ws (Node.js), websockets (Python), Socket.IO (abstração) |
| Broker de mensagens (opcional) | Distribui mensagens entre múltiplas instâncias do servidor, garantindo broadcast eficiente. | Redis Pub/Sub, NATS, RabbitMQ |
| Camada de autenticação | Verifica identidade antes de abrir o canal. | JWT, OAuth 2.0, cookies seguros |
| Monitoramento | Coleta métricas de latência, conexões ativas, erros. | Prometheus, Grafana |
Dica: Em ambientes com alta carga, separar o broker de mensagens do servidor de aplicação permite escalar horizontalmente sem perder consistência.
1.2 Fluxo de conexão
GET /ws com cabeçalhos Upgrade: websocket.101 Switching Protocols.2. Implementando o servidor
Vamos criar duas versões simples: uma em Node.js usando a biblioteca ws e outra em Python com websockets. Ambas suportam:
- Autenticação via JWT.
- Broadcast para todos os sockets conectados.
- Heartbeat (ping/pong) para detectar conexões inativas.
2.1 Node.js (arquivo server.js)
// server.js
const http = require('http');
const WebSocket = require('ws');
const jwt = require('jsonwebtoken');
const SECRET = 'sua_chave_secreta';
// Cria servidor HTTP puro (necessário para o handshake)
const server = http.createServer();
// Instancia o WebSocket Server
const wss = new WebSocket.Server({ noServer: true });
// Mapeia sockets autenticados
const clients = new Set();
function verifyToken(token) {
try {
return jwt.verify(token, SECRET);
} catch (_) {
return null;
}
}
// Quando um cliente se conecta
wss.on('connection', (ws, req, user) => {
ws.user = user; // armazena dados do usuário
clients.add(ws);
console.log(🟢 Usuário ${user.id} conectado);
// Envia mensagem de boas‑vindas
ws.send(JSON.stringify({ type: 'welcome', message: Olá, ${user.name}! }));
// Recebe mensagens do cliente
ws.on('message', (data) => {
const msg = JSON.parse(data);
if (msg.type === 'chat') {
// Broadcast para todos
const payload = JSON.stringify({
type: 'chat',
from: ws.user.name,
text: msg.text,
timestamp: Date.now(),
});
for (const client of clients) {
if (client.readyState === WebSocket.OPEN) client.send(payload);
}
}
});
// Detecta desconexão
ws.on('close', () => {
clients.delete(ws);
console.log(🔴 Usuário ${user.id} desconectado);
});
});
// Tratamento do handshake e validação do token
server.on('upgrade', (request, socket, head) => {
const token = request.headers['sec-websocket-protocol'];
const user = verifyToken(token);
if (!user) {
socket.write('HTTP/1.1 401 Unauthorized\r
\r
');
socket.destroy();
return;
}
wss.handleUpgrade(request, socket, head, (ws) => {
wss.emit('connection', ws, request, user);
});
});
server.listen(8080, () => console.log('🚀 Servidor WebSocket rodando na porta 8080'));
Pontos de atenção
- O token JWT é passado no cabeçalho
Sec-WebSocket-Protocol. Essa prática evita expor credenciais na URL. - O heartbeat padrão do
wsjá envia ping/pong a cada 30 s; pode ser configurado viaws.isAlive.
2.2 Python (arquivo server.py)
# server.py
import asyncio
import json
import jwt
import websockets
SECRET = "sua_chave_secreta"
connected = set()
def verify_token(token: str):
try:
return jwt.decode(token, SECRET, algorithms=["HS256"])
except jwt.InvalidTokenError:
return None
async def handler(websocket, path):
# Primeiro frame deve conter o token
token_msg = await websocket.recv()
token_data = json.loads(token_msg)
user = verify_token(token_data.get("token"))
if not user:
await websocket.close(code=4001, reason="Token inválido")
return
# Armazena usuário na conexão
websocket.user = user
connected.add(websocket)
print(f"🟢 Usuário {user['id']} conectado")
# Mensagem de boas‑vindas
await websocket.send(json.dumps({
"type": "welcome",
"message": f"Olá, {user['name']}!"
}))
try:
async for message in websocket:
data = json.loads(message)
if data["type"] == "chat":
payload = json.dumps({
"type": "chat",
"from": websocket.user["name"],
"text": data["text"],
"timestamp": int(asyncio.get_event_loop().time() * 1000)
})
# Broadcast
await asyncio.wait([ws.send(payload) for ws in connected if ws.open])
finally:
connected.remove(websocket)
print(f"🔴 Usuário {user['id']} desconectado")
Configura heartbeat automático (ping a cada 20s)
start_server = websockets.serve(
handler,
"0.0.0.0",
8765,
ping_interval=20,
ping_timeout=10,
)
asyncio.get_event_loop().run_until_complete(start_server)
print("🚀 Servidor Python WebSocket escutando na porta 8765")
asyncio.get_event_loop().run_forever()
Observações
- O cliente envia um JSON contendo o token antes de iniciar a troca de mensagens.
- O parâmetro
ping_intervalgarante que conexões inativas sejam fechadas automaticamente.
3. Cliente web: chat, notificações e dashboard
A seguir, um exemplo de página HTML que:
chat, notification, metric).<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Chat & Dashboard em Tempo Real</title>
<style>
body { font-family: Arial, sans-serif; margin: 2rem; }
#log { border: 1px solid #ccc; height: 300px; overflow-y: auto; padding: .5rem; }
#metrics { margin-top: 1rem; }
.msg { margin: .2rem 0; }
.notif { color: #0066cc; }
</style>
</head>
<body>
<h1>💬 Chat em tempo real</h1>
<div id="log"></div>
<input id="input" placeholder="Digite sua mensagem..." autocomplete="off"/>
<button id="sendBtn">Enviar</button>
<h2>📊 Dashboard de Métricas</h2>
<div id="metrics">
<p>CPU: <span id="cpu">-</span>%</p>
<p>Memória: <span id="mem">-</span>%</p>
</div>
<script>
// Simula obtenção de JWT (em produção, viria do login)
const jwtToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
const ws = new WebSocket(ws://localhost:8080, jwtToken);
const log = document.getElementById('log');
const input = document.getElementById('input');
const sendBtn = document.getElementById('sendBtn');
ws.onopen = () => addMsg('✅ Conexão estabelecida');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'welcome':
addMsg(🤖 ${data.message});
break;
case 'chat':
addMsg(<strong>${data.from}:</strong> ${data.text});
break;
case 'notification':
addMsg(<span class="notif">🔔 ${data.text}</span>);
break;
case 'metric':
document.getElementById('cpu').textContent = data.cpu;
document.getElementById('mem').textContent = data.mem;
break;
}
};
ws.onclose = () => addMsg('❌ Conexão encerrada');
sendBtn.onclick = () => {
const text = input.value.trim();
if (!text) return;
ws.send(JSON.stringify({ type: 'chat', text }));
input.value = '';
};
function addMsg(html) {
const p = document.createElement('p');
p.className = 'msg';
p.innerHTML = html;
log.appendChild(p);
log.scrollTop = log.scrollHeight;
}
</script>
</body>
</html>
Como funciona
- O token JWT é passado como subprotocol no construtor do
WebSocket. O servidor o valida antes de


